一、文件編碼
Unicode 是首選編碼。Unicode 是全球范圍的字符編碼標准。
小結: GBK 與unicode之間的轉換是通過gbk unicode映射表。
UTF-8 與unicode之間的轉換是通過轉換規則公式
所以說,unicode是核心中介。Gbk要轉換成utf-8的話,先轉成unicode。然后unicode再轉換成utf-8;反之亦然。
二、XML編碼問題
★ 編碼屬性應當被指定為文檔被保存時所使用的編碼
★ encoding聲明的編碼屬性
★ W3C定義了三條XML解析器如何正確讀取XML文件的編碼的規則:
1.如果文擋有BOM(字節順序標記,一般來說,如果保存為unicode格式,則包含BOM,ANSI則無),
就定義了文件編碼(另存為文件時,選擇的編碼格式)。
2.如果沒有BOM,就查看XML encoding聲明的編碼屬性。
3.如果上述兩個都沒有,就假定XML文擋采用UTF-8編碼
★ Eclipse等編輯器會根據XML encoding聲明的編碼屬性來保存文件。
★移除無效的XML字符
/** * 移除無效的XML字符
* 官方定義了XML的無效字符分為三段: 0x00 - 0x08 0x0b - 0x0c 0x0e - 0x1f
* @param value
* @return */
public static String removeInvalidXMLCharacter(String value) {
return value.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");
}
三、String編碼問題
★ 對於 String s = "你好哦!";的理解。
1、如果源碼文件是GBK編碼, 操作系統(windows)默認的環境編碼為GBK,那么編譯時, JVM將 按照GBK編碼將字節數組解析成字符,然后將字符轉換為unicode格式的字節數組,作為內部存儲。
如果源碼文件是UTF-8編碼, 我們需要通知編譯器源碼的格式,javac -encoding utf-8 ... , 編譯時,JVM按照utf-8 解析成字符,然后轉換為unicode格式的字節數組,
那么不論源碼文件是什么格式,同樣的字符串,最后得到的unicode字節數組是完全一致的,顯示的時候,也是轉成GBK來顯示(跟OS環境有關)
2、System.out.println( new String(s.getBytes(),"UTF-8")); // 錯誤,因為getBytes()默認使用GBK編碼, 而解析時使用UTF-8編碼,肯定出錯。
★如何正確的將GBK轉UTF-8 ? (實際上是unicode轉UTF-8)
注意:並不算new String( s.getBytes("GBK") , "UTF-8); //源碼文件是GBK格式,或者這個字符串是從GBK文件中讀取出來的, 轉換為string 變成unicode格式
//字符串在內存中是unicode格式
String gbkStr = "你好哦!";
//利用getBytes將unicode字符串轉成UTF-8格式的字節數組
byte[] utf8Bytes = gbkStr.getBytes("UTF-8");
//然后用utf-8 對這個字節數組解碼成新的字符串
String utf8Str = new String(utf8Bytes, "UTF-8");
即:new String( s.getBytes("utf-8") , "utf-8");
★new String(s.getBytes("iso-8859-1") ,"GBK")
一般用來轉換原來是GBK編碼的,被轉換成了iso-8859-1,現在恢復回GBK。
注意:並不是所有轉換都是可逆的,iso-8859-1的字節數組是單字節的,所以能轉換。
★讀寫時,可以指定編碼
四、JAVA編碼問題
★文件加載
java文件編碼格式:默認與操作系統一致,但可修改。
編譯成Class文件:class文件的編碼固定為UTF-8
load class文件到JVM :Unicode
內存:Unicode
理解:不管文件的編碼格式是什么,加載到JVM都是一樣的。
★網絡傳輸都是以字節為單位,所以所有的數據都必須能夠被序列化為字節。在 Java 中數據被序列化必須繼承 Serializable 接口。
★從網絡中讀取資源文件的時候,無論當前java文件編碼為何值,得到的一個個字節只與讀取的資源文件保存的編碼有關。
★對於讀取網絡資源亂碼問題,如果能夠知道資源的編碼格式,只需要在轉成字符串的過程中使用這種編碼就行。
所以,關鍵問題落在了判斷資源文件編碼方式是那種。
五、encodeURI與encodeURIComponent 與 escape
★對於不同瀏覽器編碼有些不同,所以需要編碼。兩者都是使用UTF-8編碼規則來編的
★區別 :
encodeURI用於整個URL ,對於url里面的預留符號等不進行編碼;
encodeURIComponent用於參數段,編碼更徹底:url里面的預留符號等會編碼;
escape用於對字符串進行編碼,不適用於URL。escape的0-255以外的unicode值進行編碼時輸出%u****格式,其它情況下escape,encodeURI,encodeURIComponent編碼結果相同
★ escape/unescape、encodeURI/decodeURI、encodeURIComponent/decodeURIComponent 主要的區別還有不編碼的字符個數。
1)escape不編碼的字符有69個
*、+、-、.、/、@、_、0~9、a~z、A~Z而且escape對0~255以外的unicode值進行編碼時輸出%u****格式。
2)encodeURI不編碼的字符有82個
!、#、$、&、'、(、)、*、+、,、-、.、/、:、;、=、?、@、_、~、0~9、a~z、A~Z
3)encodeURIComponent不編碼的字符有71個
!、'、(、)、*、-、.、_、~、0~9、a~z、A~Z
★對URL中的中文參數需要兩次編碼的問題。
(1)如果服務器的編碼是UTF-8,那么下面是不會出現亂碼的。否則,出現亂碼。
前端:var url1=encodeURI(url);
后台:String name=request.getParameter("name");
(2)不管服務器編碼,都不會出現亂碼
前端:url1=encodeURI(url);把url中的中文編為ASCII碼。
url2=encodeURI(url1);對ASCII碼進行編碼
后台://這里tomcat自動解碼。tomcat的配置文件沒設置,那么默認是ISO-8859-1
String name1=request.getParameter("name");
String name2 = java.net.URLDecoder.decode(name1,"UTF-8");
不管是按 GBK 還是 UTF-8 還是 ISO-8859-1 都好,都能夠正確的得到url1。因為ASCII碼的編碼用GBK、UTF-8、ISO-8859-1編碼的結果是相同的。
★對於POST提交數據,瀏覽器會根據網頁的ContentType("text/html; charset=GBK") 中指定的編碼進行對表單中的數據進行編碼。
服務端:request.setCharacterEncoding()設置編碼,然后通過request.getParameter獲得正確的數
六、JAVA中的亂碼
★瀏覽器用utf-8解析:
(手動)==> 在瀏覽器中右鍵選擇編碼格式為utf-8
(智能)==> 在文件中寫入如: <meta name="content-type" content="text/html; charset=UTF-8">
通過<meta>標簽模擬response頭,起到告訴瀏覽器用utf-8的編碼解析
(智能)==> response.setContentType("text/html;charset=utf-8");
或 response.setHeader("content-type","text/html;charset=UTF-8");
或 response.getOutputStream().write("<meta http-equiv='content-type' content='text/html;charset=utf-8'>".getBytes());
目的是為了控制瀏覽器的行為,即控制瀏覽器用UTF-8進行解碼
常用:
<meta name="content-type" content="text/html; charset=UTF-8">或<meta charset="utf-8">
<%@ pageEncoding="utf-8"%>
<?xml encoding="UTF-8"?>
★response.setCharacterEncoding("UTF-8"); 設置的是response存儲數據的碼表。 目的是用於response.getWriter()輸出的字符流的編碼。
如果是response.getOutputStream()是不需要此種解決方案的,因為這句話的意思是為了將response對象中的數據以UTF-8解碼后的字節流發向瀏覽器
★response.setContentType("text/html;charset=utf-8");內部也調用了setCharacterEncoding方法,相當於setCharacterEncoding("UTF-8");和setHeader("content-type","text/html;charset=UTF-8");
★response.setCharacterEncoding可以覆蓋之前的response.setContentType
★ 1.IE和WEB服務器默認通過ISO-8859-1進行編碼,可以使用setCharacterEncoding是設置字符的編碼
2.URL默認只支持ISO-8859-1
★ Get請求:參數QueryString內容默認解碼方式問ISO8859-1,而且使用request.setCharacterEncoding("utf-8")也無法解決問題。
1.修改tomcat服務器的配置文件<Connector>節點 URIEncoding="utf-8"
2.如果沒有設置URIEncoding,那么使用new String(username.getBytes("ISO-8859-1"),"UTF-8");
3. useBodyEncodingForURI=”true”:使用Header中ContentType中定義的Charset
★ url、cookie、ajax get請求,一般用URLEncoder,對於url參數需要兩次編碼
★ Post請求 request.setCharacterEncoding("UTF-8"); 只對Post請求有效