1. 程式人生 > >Java中scanner.next()鍵盤輸入中文亂碼以及轉碼亂碼的問題

Java中scanner.next()鍵盤輸入中文亂碼以及轉碼亂碼的問題

    在寫java程式碼的時候,遇到中文的亂碼經常是我們困擾的問題。

當我們定義:

String  s = "歡迎您光臨我的CSDN部落格";

    這個字串s的編碼是什麼呢?答案是它跟你的檔案編碼有關係,當你把檔案編碼設定為UTF-8,那麼它就是UTF-8的。

在設定為檔案UTF-8後,可以通過:

System.out.println(Charset.defaultCharset());

    來得到預設的編碼,這裡我們設定後便打印出了“UTF-8”,我們怎麼確定這個字串s就會是UTF-8的編碼呢? 看下面的程式碼:

public class Test {

    public
static void main(String[] args) { String s = "歡迎您光臨我的CSDN部落格"; System.out.println("default charset:" + Charset.defaultCharset()); try { System.out.println("UTF-8:" + new String(s.getBytes(), "UTF-8")); System.out.println("GBK:" + new String(s.getBytes(), "GBK"
)); System.out.println("ISO-8859-1:" + new String(s.getBytes(), "ISO-8859-1")); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

    我們用先得到s的位元組,然後重新按照特定編碼生成新的字串。列印如下:

default charset:UTF-8
UTF-8:歡迎您光臨我的CSDN部落格
GBK:嬈㈣繋鎮ㄥ厜涓存垜鐨凜SDN鍗氬
ISO-8859-1:欢迎您光临我的CSDN博客

    可以發現只有編碼為UTF-8的才沒有亂碼。這也就說明了當我們定義string的時候寫的中文是跟檔案編碼有關的。

    而在我們檔案編碼是UTF-8的時候,用Scanner.next()輸入的中文卻是亂碼了。百度上有人說設定Scanner的編碼:

Scanner scanner = new Scanner(System.in,"UTF-8");

    但是測試之後發現沒起作用。在我們的windows平臺預設用的是gbk的編碼,而輸入的時候也就是gbk了,和檔案的編碼是兩回事。那麼我們可以在輸入的時候經過:

new String(s.getBytes("GBK"), Charset.defaultCharset());

    這樣就可以吧我們輸入的中文字元轉換為我們設定的檔案編碼。所以在鍵盤輸入的中文就不會造成亂碼了。當然也可以直接寫:

new String(s.getBytes("GBK"),“UTF-8”);

    要注意的就是你要的編碼之後的字串一定要跟你檔案編碼一樣才不會造成亂碼。

    另外一個在轉碼的時候,如果知道字串是什麼編碼的話,就得在得到位元組陣列的時候傳入編碼,才能夠正確的讀取到位元組陣列。

    那麼,s.getBytes(“GBK”)和s.getBytes()什麼區別?

    什麼時候用xxx.getBytes(XXX),什麼時候用xxx.getBytes()?

我們來看一下.getBytes()的原始碼:

public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }

再看StringCoding的encode:

 static byte[] encode(char[] ca, int off, int len) {
        String csn = Charset.defaultCharset().name();
        try {
            // use charset name encode() variant which provides caching.
            return encode(csn, ca, off, len);
        } catch (UnsupportedEncodingException x) {
            warnUnsupportedCharset(csn);
        }
        try {
            return encode("ISO-8859-1", ca, off, len);
        } catch (UnsupportedEncodingException x) {
            // If this code is hit during VM initialization, MessageUtils is
            // the only way we will be able to get any kind of error message.
            MessageUtils.err("ISO-8859-1 charset not available: "
                             + x.toString());
            // If we can not find ISO-8859-1 (a required encoding) then things
            // are seriously wrong with the installation.
            System.exit(1);
            return null;
        }
    }

    可以看到第一句,String csn = Charset.defaultCharset().name(); 當我們直接用getBytes()的時候會預設使用預設的檔案編碼來獲取位元組。

    那麼如果你的字串本身的編碼和檔案的編碼不同的話,這樣getBytes()那麼就會出錯了。

所以答案就是:
    除非我們是知道字串的編碼和檔案的一樣,而想要轉換成其他編碼的時候才可以用getBytes(),否則就要用getBytes(String charsetName),才能得到正常的檔案編碼。