標籤:編碼 中文 stream 擷取 簡單 locate 控制字元 返回結果 writer
一、常見的編碼格式1.ASCII
基礎編碼,英文和西歐字元。
用一個位元組的低7位表示,一共128個。
0~13是控制字元如換行、斷行符號、刪除等,32~126是列印字元,鍵盤輸入。
2.IOS-8859-1
ASCII的擴充。
用一個位元組表示,一共256個。
3.GB2312
中文編碼字元集。
用兩個位元組表示,A1~A9是符號區,一共682個;B0~F7是漢字區,一共6763個。
編碼需要查詢對應碼錶,效率略低。
4.GBK
GB2312的擴充,能夠相容GB2312。
用兩個位元組表示,一共23940個碼位,表示21003個漢字。
編碼需要查詢對應碼錶,效率略低。
5.UTF-16
UTF-16具體定義了Unicode字元在電腦的存取方法。
用兩個位元組表示Unicode的轉化格式。
定長的展示方法,每兩個位元組表示一個字元,轉化效率高,記憶體和硬碟多用此編碼(JAVA記憶體儲存格式UTF-16)。
採用順序編碼,不能對單個字元的編碼進行校正,如果損壞,後面的碼值都會受影響。
6.UTF-8
UTF-8具體定義了Unicode字元在電腦的存取方法。
用1-6個位元組組成一個字元,漢字採用三個位元組表示。
變長的展示方法,每個編碼地區有不同的字碼長度。
網路傳輸中很大一部分字元用一個位元組就可以展示,UTF-16正常化的全部轉為了兩個位元組,對於這些字元UTF-8隻需要一個位元組。
UTF-8如果中間一個碼值損壞,後面的碼值並不受影響。
相對於UTF-16,UTF-8有傳輸中資源佔用小,資料更安全的優勢,更適合網路傳輸,但UTF-16的編碼規則相對簡單,編碼效率更高,適合本地記憶體和磁碟。
二、常見JAVA編碼API1.I/O
InputStreamReader isr = new InputStreamReader(inputStream,"utf-8");Charset StreamDecoderOutputStreamWriter osw = new OutputStreamWriter(outputStream,"utf-8");Charset StreamEncoder
2.記憶體操作
字元與位元組的轉換:
//String
String s = "中文字元";byte[] b = s.getBytes("UTF-8");String s1 = new String(b,"UTF-8");
//Charset
Charset charset = Charset.forName("UTF-8");
ByteBuffer byteBuffer = charset.encode(string);
CharBuffer charBuffer = charset.decode(byteBuffer);
//char和byte的軟轉換,將一個16bit的char拆分成兩個8bit的byte來顯示,實際值並沒有被轉換。
ByteBuffer heapByteBuffer = ByteBuffer.allocate(1024);
ByteBuffer byteBuffer = heapByteBuffer.putChar(c);
三、Java Web中涉及的編解碼1.URL編解碼
PathInfo中文問題:
配置tomcat的server.xml:
<Connector URIEncoding="UTF-8"/>
QueryString中文問題:
QueryString是通過HTTP中的Header傳到背景,他的解碼字元集預設是ISO-8859-1,
也可以通過Header的ContentType中的Charset來定義。
如何確定後端調取了ContentType中的字元集,需要在server.xml中配置(這個配置只針對QueryString有效):
<Connector useBodyEncodingForURI="true"/>
2.HTTP Header的編解碼
針對Header中的其他參數,比如Cookie,redirectPath等。
盡量不要傳遞非ASCII字元,如果必須,在傳遞之前用下面的API進行編碼再傳遞:
org.apache.catalina.util.URLEncoder
3.POST表單的編解碼
用戶端擷取參數為亂碼後的解決思路:
1.將POST改為get,查看瀏覽器端是否有問題。
2.後端request.geCharacterEncdoing返回結果是否是預期編碼。
//在第一次使用request.getParameter之前使用request.setCharacterEncoding(charset);
4.HTTP BODY的編解碼
主要闡述從後台到前台的編解碼:
//對返回前台的資料進行編碼,前台會首先根據這個值進行解碼response.setCharacterEncoding(charset);
<!-- 如果後台沒有設定,會根據頁面中的charset來解碼,如果頁面也有設定則用預設編碼來解碼 --><meta HTTP-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<!-- JDBC讀寫資料時要和資料的內建編碼保持一致 -->url="jdbc:mysql://localhost:3306/DB?useUnicode=true&characterEncoding=UTF-8"
四、JS的編碼問題1.外部引入js檔案
<!-- 瀏覽器會按照charset的設定來解析這個js檔案,如果沒有設定則預設按照當前頁面的的編碼設定來解析js檔案 --><script src="de/mo/demo.js" charset="gbk"></script>
2.js的URL編碼
//對url根據UTF-8進行編碼和解碼,除了一些特殊字元"!""#""$""&""‘""("")""*""+"",""-"".""/"":"";""=""?""@""_""~""0-9""a-z""A-Z"
//編碼結果在每個碼值前加一個"%"
encodeURI("http://localhost:8080/examples/servlets/servlet/來吧昆特牌吧孫子?inviter=傑洛特");
decodeURI("**編碼內容**");
//對url根據UTF-8進行編碼和解碼,相對於encodeURI,它更加的徹底。排除的特殊字元為"!""‘""("")""*""-"".""_""~""0-9""a-z""A-Z"
//編碼結果在每個碼值前加一個"%"
//它排除的字元比encodeURI更少,通常用於將URL作為參數的URL的編碼,如樣本如果不將參數URL中的&進行編碼會影響到整個URL的完整性
"http://localhost/servlet?ref=" + encodeURIComponent("http://localhost:8080/examples/servlets/servlet/來吧昆特牌吧孫子?inviter=傑洛特&inviter=葉奈法");
decodeURIComponent("**編碼內容**");
3.後端接收時解碼
後端處理URL編解碼靠的是 java.net.URLEncoder和java.net.URLDecoder這兩個類。
後端對的對URL的編碼同樣也有排除的特殊字元,與前端的encodeURIComponent相對應。
//後端直接擷取傳過來的URL參數會自動解碼
//如果沒有提前設定request.setCharacterEncoding()很容易出現編碼不同而導致的亂碼
request.getParameter();
//另一種方式是通過前台js對URL進行兩次編碼,後台不管通過什麼進行第一次解碼,都能得到正確的UTF-8編碼,前台代碼如下
encodeURIComponent(encodeURIComponent(url));
//第一次編碼的結果(例如:%E2%A7)的百分比符號,會在第二次編碼後將%變成%25(例如:%25E2%25A7)
//後台在執行request.getParameter()的時候會自動解碼,不管當前容器的編碼是什麼得到的是正確的UTF-8編碼(例如:%E2%A7)
五、其他需要編碼的地方1.xml
<?xml version="1.0" encoding="UTF-8"?>
2.Velocity
services.VelocityService.input.encoding=UTF-8
3.JSP
<%@page contentType="text/html;charset=UTF-8"%>
註:本文是對“《深入分析Java Web技術內幕》許令波 著” 一書的相關內容的總結
java編碼,亂碼問題詳解