任我行
將GB2312格式字符串變為ISO-8859-1需要用到中間輔助類byte,原理是講字符串轉化成byte,然后將byte轉換成字符串同時轉碼,當然要注意異常的捕捉。
這個過程大致分為2個步驟:
將字符串轉換成byte。
將byte轉換成字符串,同時設置編碼格式為ISO-8859-1。
操作過程如下圖所示
卷啊卷
給你些詳細資料解釋
1、JVM中單個字符占用的字節長度跟編碼方式有關,而默認編碼方式又跟平臺是一一對應的或說平臺決定了默認字符編碼方式;
2、對于單個字符:ISO-8859-1單字節編碼,GBK雙字節編碼,UTF-8三字節編碼;因此中文平臺(中文平臺默認字符集編碼GBK)下一個中iso14001環境管理體系認證符占2個字節,而英文平臺(英文平臺默認字符集編碼Cp1252(類似于ISO-8859-1))。
3、getBytes()、getBytes(encoding)函數的作用是使用系統默認或者指定的字符集編碼方式,將字符串編碼成字節數組。
Me結論:編碼方式決定字節長度;
在中文平臺下,默認的字符集編碼是GBK,此時如果使用getBytes()或者getBytes("GBK"),則按照GBK的編碼規則將每個中iso14001環境管理體系認證符用2個byte表示。所以我們看到"中文"最終GBK編碼結果就是: -42 -48 -50 -60 。-42和-48代表了"中"字,而"-50"和"-60"則代表了"文"字。
在中文平臺下,如果指定的字符集編碼是UTF-8,那么按照UTF-8對中文的編碼規則:每個中文用3個字節表示,那么"中文"這兩個字符最終被編碼成:-28 -72 -8
3、-26 -106 -121兩組。每3個字節代表一個中iso14001環境管理體系認證符。
在中文平臺下,如果指定的字符集編碼是ISO-8859-1,由于此字符集是單字節編碼,所以使用getBytes("ISO-8859-1")時,每個字符只取一個字節,每個漢字只取到了一半的字符。另外一半的字節丟失了。由于這一半的字符在字符集中找不到對應的字符,所以默認使用編碼63代替,也就是?。
在英文平臺下,默認的字符集編碼是Cp1252(類似于ISO-8859-1),如果使用GBK、UTF-8進行編碼,得到的字節數組依然是正確的(GBK4個字節,UTF-8是6個字節)。因為在JVM內部是以Unicode存儲字符串的,使用getBytes(encoding)會讓JVM進行一次Unicode到指定編碼之間的轉換。對于GBK,JVM依然會轉換成4個字節,對于UTF-8,JVM依然會轉換成6個字節。但是對于ISO-8859-1,則由于無法轉換(2個字節--->1個字節,截取了一半的字節),所以轉換后的結果是錯誤的。
相同的平臺下,同一個中iso14001環境管理體系認證符,在不同的編碼方式下,得到的是完全不同的字節數組。這些字節數組有可能是正確的(只要該字符集支持中文),也可能是完全錯誤的(該字符集不支持中文)。
記?。?/p>
不要輕易地使用或濫用String類的getBytes(encoding)方法,更要盡量避免使用getBytes()方法。因為這個方法是平臺依賴的,在平臺不可預知的情況下完全可能得到不同的結果。如果一定要進行字節編碼,則用戶要確保encoding的方法就是當初字符串輸入時的encoding。
【結論】字節數組轉換成字符串,然后轉換成字符數組問題:
________________________________________
和getBytes(encoding)不同,toCharArray()返回的是"自然字符"。但是這個"自然字符"的數目和內容卻是由原始的編碼方式決定的。來看看里面是如何進行字符串的操作的:
String encodedString = new String(content.getBytes(), encoding);
char charArray = inStr.toCharArray();
可以看到系統首先對原始字符串按照默認的編碼方式進行編碼,得到一個字節數組,然后按照指定的新的編碼方式進行解碼,得到新的編碼后的字符串。再轉換成對應的字符數組。
由于在中文平臺下,默認的字符集編碼是GBK,于是content.getBytes()得到的是什么呢?就是下面這4個字節:
byte[0] = -42 hex string = ffffffd6
byte[1] = -48 hex string = ffffffd0
byte[2] = -50 hex string = ffffffce
byte[3] = -60 hex string = ffffffc4
如果新的encoding是GBK,那么經過解碼后,由于一個字符用2個字節表示。于是最終的結果就是:
char[0]='中' --- byte[0] + byte[1]
char[1]='文' --- byte[2] + byte[3]
如果新的encoding是ISO-8859-1,那么經過解碼后,由于一個字符用1個字節表示,于是原來本應該2個字節一起解析的變成單個字節解析,每個字節都代表了一個漢字字符的一半。這一半的字節在ISO-8859-1中找不到對應的字符,就變成了"?"了,最終的結果:
char[0]='?' ---- byte[0]
char[1]='?' ---- byte[1]
char[2]='?' ---- byte[2]
char[3]='?' ---- byte[3]
如果新的encoding是UTF-8,那么經過解碼后,由于一個字符用3個字節表示,于是原來4個字節的數據無法正常的解析成UTF-8的數據,最終的結果也是每一個都變成"?"。
char[0]='?' ---- byte[0]
char[1]='?' ---- byte[1]
char[2]='?' ---- byte[2]
char[3]='?' ---- byte[3]
如果是在英文平臺下,由于默認的編碼方式是Cp1252,于是content.getBytes()得到的字節都是被截去一半的殘留字符,所以我們看到在英文平臺下,不論指定的encoding是GBK、UTF-8,其結果和ISO-8859-1都是一樣的。
記?。?/p>
這個方法再次證明了String的getBytes()方法的危險性,如果我們使用new String(str.getBytes(), encoding)對字符串進行重新編碼解碼時,我們一定要清楚str.getBytes()方法返回的字節數組的長度、內容到底是什么,因為在接下來使用新的encoding進行編碼解碼時,Java并不會自動地對字節數組進行擴展以適應新的encoding。而是按照新的編碼方法直接對該字節數組進行解析。
于是結果就像上面的例子一樣,同樣是4個原始字節,有些每2個一組進行解析,有些每個一組進行解析,有些每3個一組進行解析。其結果就只能看那種編碼方式合適了。
【結論】
FileWriter是字符流輸出流,而OutputStreamWriter是字節流輸出流
①在中文平臺下,如果使用FileWriter,不論你如何設置字符集都不會起作用。因為它采用的是默認的系統字符集。即便你設置了System.setProperty("file.encoding", "ISO-8859-1"),或者在運行時給予參數-Dfile.encoding=UTF-8都不會起作用。你會發現它最終還是都已"GB2312"或者"GBK"的方式保存。
在中文平臺下,如果使用OutputStreamWriter,則在后臺寫入時會把字符流轉換成字節流,此時指定的編碼字符集就起作用了。可以看到在指定GBK、UTF-8的情況下中文可以正常的保存和讀取,同時iso三體系認證按照我們給定的方式保存了。而對于ISO-8859-1則變成了?,這再次證明了采用ISO-8859-1是不能保存中文的,而且會因為中文編碼在ISO-8859-1的編碼中找不到對應的字符而默認轉換成?。
②在英文平臺下,如果使用FileWriter,不論你如何設置字符集同樣都不會起作用。所有的iso三體系認證都將按照ISO-8859-1的編碼方式保存,毫無疑問地變成了?。在英文平臺下,如果使用OutputStreamWriter,則只有當我們把字符和iso三體系認證的編碼方式正確設置為GBK、UTF-8的情況下,中文才能正確的保存并顯示。
③通過上述的實驗證明,為了確保在不同的平臺下,客戶端輸入的中文可以被正確地解析、保存、讀取。最好的辦法就是使用OutputStreamWriter配合UTF-8編碼。
如果不想使用UTF-8編碼,那么可以考慮使用GB2312,不建議使用GBK、GB18030。因為對于某些老式的文本編輯器,甚至不支持GBK、GB18030的編碼,但是對于GB2312則是一定支持的。因為前兩者都不是國標但后者是。
④關于String的getBytes(),getBytes(encoding)和new String(bytes, encoding)這三個方法,非常值得注意:
A.getBytes():使用平臺默認的編碼方式(通過file.encoding屬性獲取)方式來將字符串轉換成byte。得到的是字符串最原始的字節編碼值。
B.getBytes(NAME_OF_CHARSET):使用指定的編碼方式將字符串轉換成byte,如果想要得到正確的字節數組,程序員必須給出正確的NAME_OF_CHARSET。否則得到的就不會得到正確的結果。
C.new String(bytes, encoding):如果我們在客戶端使用UTF-8編碼的JSP頁面發出請求,瀏覽器編碼后的UTF-8字節會以ISO-8859-1的形式傳遞到服務器端。所以要得到經HTTP協議傳輸的原始字節,我們需要先調用getBytes("ISO-8859-1")得到原始的字節,但由于我們客戶端的原始編碼是UTF-8,如果繼續按照ISO-8859-1解碼,那么得到的將不是一個中iso14001環境管理體系認證符,而是3個亂碼的字符。所以我們需要再次調用new String(bytes,"UTF-8"),將字節數組按照UTF-8的格式,每3個一組進行解碼,才能還原為客戶端的原始字符。
D.String的getBytes()、getBytes(NAME_OF_CHARSET)方法都是比較微妙的方法,原則上:傳輸時采用的是什么編碼,我們就需要按照這種編碼得到字節。new String(bytes, NAME_OF_CHARSET)則更加需要小心,原則上:客戶端采用的是什么編碼,那么這里的NAME_OF_CHARSET就必須和客戶端保持一致。
例如JSP頁面是GBK,那么我們接收頁面傳遞而來的參數時就必須使用new String(parameter.getBytes("ISO-8859-1"), "GBK");如果使用了錯誤的解碼方式,如使用了UTF-8,那么得到的很有可能就是亂碼了。
也就是說:GBK--->ISO-8859-1--->GBK、UTF-8--->ISO-8859-1--->UTF-8的轉換過程是沒有問題的。但是GBK--->ISO-8859-1--->UTF-
8、UTF-8--->ISO-8859-1--->GBK的字節直接轉碼則可能導致亂碼,需要另外的轉換過程。
記?。?/p>
謹慎地使用getBytes(NAME_OF_CHARSET)和new String(bytes, NAME_OF_CHARSET),除非你很清楚的知道原始的字符編碼和傳輸協議使用的編碼。
推薦使用基于服務器的配置、過濾器設置request/response的characterEncoding、content type屬性。還有就是JSP頁面的pageEncoding屬性、HTML meta元素的content type屬性。盡量避免頻繁的在代碼中進行字符串轉碼,即降低了效率又增加了風險。
別來無恙
JAVA有一個public String(byte bytes, Charset charset)函數可以用指定字節數組和編碼來構造字符串。一個public byte getBytes(Charset charset)函數把字符串按指定編碼來得到字節數組。可以用這兩個函數來實現編碼轉換。
下面是一個簡單的例子,注意一下例子中的iso14001環境管理體系認證本身的編碼,最好在自己的環境中用gb2312重新輸入,不然可能是亂碼。當然轉換后輸出肯定有一個是亂碼,也肯能都是亂碼。根據你的編輯器的編碼格式有關。
public class EncodingTest
{
public static void main(String args)
{
try
{
String gb = new String("國標2312".getBytes(),"gb2312");
System.out.println(gb);
byte b = gb.getBytes("gb2312");
String ios = new String(b,"ISO-8859-1");
System.out.println(ios);
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
}
咿呀呀
/**
* 最底層字符串編碼轉換的實現方法
*
* @param str
* 待轉換的字符串
* @param oldCharset
* 源字符集
* @param newCharset
* 目標字符集
* @return 轉換后的字符串
*/
public static String changeCharset(String str, String oldCharset, String newCharset) {
if (str != null) {
// 用源字符編碼解碼字符串
try {
return new String(str.getBytes(oldCharset), newCharset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return null;
}
oldCharset 為"GB2312"
newCharset 為“ISO-8859-1”
再睡一夏
通過JDK
1.6知道String類中getBytes(”編碼“)方法可以講一個數用指定的編碼轉成一個字節數組,String中通過指定的 charset解碼指定的 byte 數組,構造一個新的 String。代碼如下:
try{
String s = "java學習";
System.out.println(s);
String result = new String(s.getBytes("GB2312"),"iso-8859-1");
System.out.println(s);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
擴展資料:
getBytes() 方法有兩種形式:
1、getBytes(String charsetName): 使用指定的字符集將字符串編碼為 byte 序列,并將結果存儲到一個新的 byte 數組中。
2、getBytes(): 使用平臺的默認字符集將字符串編碼為 byte 序列,并將結果存儲到一個新的 byte 數組中。
參考資料: