程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> String.getBytes()方法中的中文編碼問題

String.getBytes()方法中的中文編碼問題

編輯:關於JAVA

String的getBytes()方法是得到一個字串的字節數組,這是眾所周知的。但特別要注意的是,本方法將返回該操作系統默認的編碼格式的字節數組。如果你在使用這個方法時不考慮到這一點,你會發現在一個平台上運行良好的系統,放到另外一台機器後會產生意想不到的問題。比如下面的程序:

class TestCharset 
{

    public static void main(String[] args) 
    {
        new TestCharset().execute();
    }

    private void execute() {
        String s = "Hello!你好!";
        
        byte[] bytes = s.getBytes();

        System.out.println("bytes
  lenght is:" + bytes.length);


    }

}

在一個中文WindowsXP系統下,運行時,結果為:

bytes lenght is:12

 但是如果放到了一個英文的UNIX環境下運行:

$ Java TestCharset
bytes lenght is:9

如果你的程序依賴於該結果,將在後續操作中引起問題。為什麼在一個系統中結果為12,而在另外一個卻變成了9了呢?上面已經提到了,該方法是和平台(編碼)相關的。

在中文操作系統中,getBytes方法返回的是一個GBK或者GB2312的中文編碼的字節數組,其中中文字符,各占兩個字節。而在英文平台中,一般的默認編碼是“ISO-8859-1”,每個字符都只取一個字節(而不管是否非拉丁字符)。

Java中的編碼支持

Java是支持多國編碼的,在Java中,字符都是以Unicode進行存儲的,比如,“你”字的Unicode編碼是“4f60”,我們可以通過下面的實驗代碼來驗證:

class TestCharset 
{

    public static void main(String[] args) 
    {
        char c = '你';
        int i = c;
        System.out.println(c);
        System.out.println(i);
    }

}

不管你在任何平台上執行,都會有相同的輸出:

20320

20320就是Unicode “4f60”的整數值。其實,你可以反編譯上面的類,可以發現在生成的.class文件中字符“你”(或者其它任何中文字串)本身就是以Unicode編碼進行存儲的:

char c = '\u4F60';
        ... ...

即使你知道了編碼的編碼格式,比如:

javac -encoding GBK TestCharset.Java

編譯後生成的.class文件中仍然是以Unicode格式存儲中文字符或字符串的。使用String.getBytes(String charset)方法

所以,為了避免這種問題,我建議大家都在編碼中使用String.getBytes(String charset)方法。下面我們將從字串分別提取ISO-8859-1和GBK兩種編碼格式的字節數組,看看會有什麼結果:


class TestCharset 
{

    public static void main(String[] args) 
    {
        new TestCharset().execute();
    }

    private void execute() {
        String s = "Hello!你好!";
        
        byte[] bytesISO8859 =null;
        byte[] bytesGBK = null;

        try
        {
            bytesISO8859 =
   s.getBytes("iso-8859-1");
            bytesGBK = s.getBytes("GBK");
        }
        catch
  (Java.io.UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }

        System.out.println
  ("--------------
  \n 8859 bytes:");
        System.out.println("bytes is:     " + arrayToString(bytesISO8859));
        System.out.println("hex format is:"
  + encodeHex(bytesISO8859));
        System.out.println();

        System.out.println
  ("--------------
  \n GBK bytes:");
        System.out.println("bytes is:   
  " + arrayToString(bytesGBK));
        System.out.println("hex format
  is:" + encodeHex(bytesGBK));

    }

    public static final String
 encodeHex (byte[] bytes)
 {
        StringBuffer buff =
  new StringBuffer(bytes.length * 2);
        String b;
        for (int i=0; i< bytes.length ; i++)
        {
            b = Integer.toHexString(bytes[i]); 
            // byte是兩個字節的,
   而上面的Integer.toHexString會把字節擴展為4個字節
            buff.append(b.length() > 2 ? b.substring(6,8) : b); 
            buff.append(" ");
        }
        return buff.toString();
    }

    public static final String
 arrayToString (byte[] bytes)
 {
        StringBuffer buff = new StringBuffer();
        for (int i=0; i< bytes.length ; i++)
        {
            buff.append(bytes[i] + " ");
        }
        return buff.toString();
    }

}

執行上面程序將打印出:

--------------
 8859 bytes:
bytes is:     72 101 108 108 111 33 63 63 63
hex format is:48 65 6c 6c 6f 21 3f 3f 3f

--------------
 GBK bytes:
bytes is:     72 101 108 108 111 33
-60 -29 -70 -61 -93 -95
hex format is:48 65 6c 6c 6f 21 c4 e3 ba c3 a3 a1

可見,在s中提取的8859-1格式的字節數組長度為9,中文字符都變成了“63”,ASCII碼為63的是“?”,一些國外的程序在國內中文環境下運行時,經常出現亂碼,上面布滿了“?”,就是因為編碼沒有進行正確處理的結果。

而提取的GBK編碼的字節數組中正確得到了中文字符的GBK編碼。字符“你”“好”“!”的GBK編碼分別是:“c4e3”“bac3”“a3a1”。得到了正確的以GBK編碼的字節數組,以後需要還原為中文字串時,可以使用下面方法:

new String(byte[] bytes,
String charset)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved