Java語言能夠這麼普遍的應用,與其國際化的能力是分不開的,國際化的編碼是Java國際化中最重要的一個組成部分,Java的國際化編碼能力與其使用Unicode編碼是直接相關的。在Java中,任何字元類型的資料在Java程式中均以Unicode字元表示,比如char、String等類型。註:本文實驗環境為Windows XP中文版和JDK1.5。
一、getBytes()當Java程式從輸入資料流、檔案或字元文字量等途徑獲得字串時,均會做字元編碼的轉換,例如InputStreamReader的建構函式中就需要指定編碼方式,而對於從檔案和字元文字量中獲得字串時,均採用系統預設的編碼方式對字元資料進行解碼。考慮下面一段代碼:
String str=”中”; |
① |
byte[] bytes = str.getBytes(); |
② |
bytes = str.getBytes(“ISO-8859-1”); |
③ |
語句①:將一個只含有一個字元“中”的字串文字量賦給String類的一個對象str,字元文字量“中”是按照作業系統預設編碼方式進行編碼,在中文windows系統中通常是“GBK”, “中”在GBK編碼中是0xD6D0,在將該字元賦給str時,Java會對該字串進行編碼轉換,即將GBK編碼方式的“中”轉換成Unicode編碼方式的“中”,Unicode編碼方式“中”的編碼是0x4E2D,所以str在程式運行期間在記憶體中的二進位表示成16進位就是0x4E2D。語句②:獲得str字串的二進位形式。getBytes(String encoding)方法需要指定編碼方式,表示獲得該字串在何種編碼方式中的二進位形式。此語句中沒有設定參數,表示採用作業系統預設的編碼方式,即此處獲得的bytes是“中”在GBK編碼中的二進位形式,即bytes[0]=0xD6, bytes[1]=0xD0。語句③:該語句與語句②的區別就是指定了編碼方式,此處指定的是ISO-8859-1,即通常所說的Latin-1,該編碼採用8bit對字元編碼,所以編碼空間中只有256個字元。該編碼中只包含了基本的ASCII碼和一些擴充的其它西歐字元,所以該字元集中不可能包含中文的“中”字,也就是說Java虛擬機器無法在ISO-8859-1編碼集中找到“中”字對應的編碼,針對這種情況,就只返回一個問號(?,0x3f)字元,所以此時bytes.length只有1,且bytes[0]=0x3f。
二、new String(byte[] bytes, String encoding)getBytes ()方法從字串獲得二進位的位元組數組。如果要從二進位的位元組數組獲得字串,則就需要使用new String(byte[] bytes, String encoding)方法,該方法按照encoding編碼方法對位元組數組bytes中的位元組進行解析,產生一個新的字串對象。
byte[] bytes = {(byte)0xD6, (byte)0xD0, (byte)0x31}; |
① |
String str = new String(bytes); |
② |
str = new String(bytes,”ISO-8859-1”); |
③ |
語句①:定義一個位元組數組。語句②:將該位元組數組中的位元據按照預設的編碼方式(GBK)編碼成字串,我們知道GBK中0xD6 0xD0表示“中”,0x31表示字元“1”(GBK相容ASCII,但不相容ISO-8859-1除ASCII之外的部分),所以str得到的值是“中1”。語句③:該句用ISO -8859-1編碼方式對該位元組資料進行編碼,由於在ISO-8859-1編碼方式中一個位元組會被解析成一個字元,所以該位元組數組會被解釋成包含三個字元的字串,但由於在ISO-8859-1編碼方式中沒有對應0xD6和0xD0的字元,所以前兩個字元會產生兩個問號,由於0x31在ISO-8859- 1編碼中對應字元“1”(ISO-8859-1也相容ASCII),所以此語句得到str的值是“??1”。
三、編碼轉換上面介紹的兩個語句是解決Java中編碼問題的基本語句,而且一般的亂碼問題也都可以通過配合使用以上兩個語句來解決。例如將InputStream中以UTF-8編碼方式編碼的字元資料轉換成為GBK編碼的位元組數組:
public byte[] Transmit(InputStream UTFIStream){ |
BufferedReader reader = new BufferedReader(new InputStreamReader(UTFIStream),”UTF-8”); |
StringBuffer content = new StringBuffer(); |
String temline; |
while((temline=reader.readLine()) != null) |
{ |
content.append(temline + “/n”); |
} |
return content.toString().getBytes(“GBK”); |
} |
四、mysql亂碼問題
mysql中的預設字元編碼方式為latin1,也即ISO-8859-1,而java中預設的字元編碼方式為Unicode,因此在java中訪問存取mysql時會出現中文亂碼問題。解決方案是:在儲存mysql之前,將中文字元由GBK編碼轉換成latin1編碼;從mysql取資料之後,將latin1編碼轉換成GBK編碼。轉換函式如下:
public static String GBKTolatin1(String str)
{
if(str==null)
{
str="";
}
else{
try{
str=new String(str.getBytes("GBK"),"ISO-8859-1");
}
catch(Exception ex){
ex.printStackTrace();
}
}
return str;
}
public static String latin1ToGBK(String str)
{
try {
str=new String(str.getBytes("ISO-8859-1"),"GBK");
return str;
}catch (UnsupportedEncodingException ex) {
System.out.println(ex);
return "";
}
}