Java IO(01) 編碼問題(一)

Java IO(01) 編碼問題(一)

IO是Java中的一塊比較重要的知識,在日常開發中應用廣泛,現對Java IO知識進行整理歸納。

在IO之前呢,用幾篇文章介紹一下Java中的編碼以及File類的基本使用。本篇文章先來簡單介紹編碼。

為了更直觀的解釋各種編碼以及對他們進行比較我們用幾個簡單的例子來說明。

程式碼1

/**
* 測試不同的編碼格式,為方便顯示,將位元組序列以16進位制形式顯示,並且輸出只顯示有效的低8位
* 具體方式是Integer.toHexString(byte[n] & 0xff)
*/
public class Encode {
public static void main(String[] args) throws Exception{
String s = "測試ABC";
//使用IDE預設的編碼格式進行位元組序列轉換,這裡的預設編碼方式是"utf-8"
byte[] b = s.getBytes();
System.out.print("預設utf-8編碼:");
for(byte bt : b) {
System.out.print(Integer.toHexString(bt & 0xff)   " ");
}
}
}

執行結果:

預設utf-8編碼:e6 b5 8b
e8 af 95 41
42 43 

上面這段程式碼中字串s中包含了中英文的內容,下面仍舊用這個字串進行舉證。通過上面這個例子可以看出來字串“測試ABC”進行了位元組序列轉換後變成了一串二進位制,我們用十六進位制的形式將其輸出顯示,最終執行結果如上。這段字串佔據了9個位元組,一個漢字用三個位元組表示,一個英文字元用一個位元組表示。s.getBytes()可以看出,我們沒有設定任何編碼格式,使用的IDE預設的編碼格式進行位元組序列轉換,這裡預設的編碼格式是“utf-8”格式。

程式碼2

/**
* 測試不同的編碼格式,為方便顯示,將位元組序列以16進位制形式顯示,並且輸出只顯示有效的低8位
* 具體方式是Integer.toHexString(byte[n] & 0xff)
*/
public class Encode {
public static void main(String[] args) throws Exception{
String s = "測試ABC";
//顯性地設定"utf-8"編碼,由於IDE預設也是該編碼方式,所以輸出結果應該相同
byte[] b2 = s.getBytes("utf-8");
System.out.print("顯性設定utf-8編碼: ");
for (byte bt : b2){
System.out.print(Integer.toHexString(bt & 0xff)   " ");
}
}
}

執行結果:

顯性設定utf-8編碼:  e6 b5 8b
e8 af 95
41 42
43 

程式碼2和程式碼1的區別就是s.getBytes(“utf-8”),這樣的更明顯地對位元組序列轉換地編碼格式做出了要求,這裡設定成“utf-8”格式,從結果上看和程式碼1的執行結果沒有任何區別,實際上本來也不會有區別,這裡也證明了預設的編碼格式是“utf-8”。

程式碼3

/**
* 測試不同的編碼格式,為方便顯示,將位元組序列以16進位制形式顯示,並且輸出只顯示有效的低8位
* 具體方式是Integer.toHexString(byte[n] & 0xff)
*/
public class Encode {
public static void main(String[] args) throws Exception{
String s = "測試ABC";
//進行"gbk"格式的位元組序列轉換
byte[] b1 = s.getBytes("gbk");
System.out.print("gbk編碼:");
for (int i = 0; i < b1.length ; i  ) {
System.out.print(Integer.toHexString(b1[i] &0xff)   " ");
}
}
}

執行結果:

gbk編碼:b2 e2
ca d4
41 42
43
 

程式碼3換了一種編碼格式,也是我們經常見到的編碼格式“gbk”,可以看出來它與“utf-8”編碼格式的區別,“gbk”編碼中文字元佔兩個字元,英文佔一個字元,所以這段字串使用這種編碼就佔據了7個位元組。

程式碼4

/**
* 測試不同的編碼格式,為方便顯示,將位元組序列以16進位制形式顯示,並且輸出只顯示有效的低8位
* 具體方式是Integer.toHexString(byte[n] & 0xff)
*/
public class Encode {
public static void main(String[] args) throws Exception{
String s = "測試ABC";
//java屬於雙位元組編碼,一個字元佔兩個位元組,這種編碼格式就是"utf-16be"
byte[] b3 = s.getBytes("utf-16be");
System.out.print("java雙位元組utf-16be編碼:");
for (byte bt : b3){
System.out.print(Integer.toHexString(bt &0xff)   " ");
}
}
}

執行結果:

java雙位元組utf-16be編碼:6d 4b
8b d5
0 41
0 42
0 43
 

程式碼4展示了java的雙位元組編碼,根據執行結果可以看出,無論中文還是英文,都佔據了兩個位元組,這就是“utf-16be”雙位元組編碼。

程式碼5

/**
* 測試不同的編碼格式,為方便顯示,將位元組序列以16進位制形式顯示,並且輸出只顯示有效的低8位
* 具體方式是Integer.toHexString(byte[n] & 0xff)
*/
public class Encode {
public static void main(String[] args) throws Exception{
String s = "測試ABC";
//java屬於雙位元組編碼,一個字元佔兩個位元組,這種編碼格式就是"utf-16be"
byte[] b3 = s.getBytes("utf-16be");
System.out.print("java雙位元組utf-16編碼:");
for (byte bt : b3){
System.out.print(Integer.toHexString(bt &0xff)   " ");
}
/**
* 當一個 位元組序列想變成字串,那麼位元組序列是什麼編碼格式,
* 則轉換成字串也要用這種編碼形式,否則就會出現亂碼的情況
*/
//按照原編碼格式"utf-16be"進行轉換
String s3 = new String(b3,"utf-16be");
System.out.println();
System.out.println("utf-16be進行轉換:" s3);
//"utf-16be"編碼格式的位元組序列使用IDE預設的"utf-8"格式進行轉換結果會亂碼
String s4 = new String(b3);
System.out.println("使用IDE預設的utf-8格式進行轉換:" s4);
}
}

執行結果:

java雙位元組utf-16be編碼:6d 4b 8b d5 0 41 0 42 0
43 

utf-16be進行轉換:測試 ABC

使用IDE預設的utf-8格式進行轉換:mK�� A B C

程式碼5表示的是將經過“utf-16be”編碼格式後生成的位元組序列進行字串的轉換,執行結果可以看出來,通過轉換成位元組序列的編碼方式”utf-16be“進行轉換的結果和源字串相同,而通過IDE自身預設的”utf-8“編碼方式進行轉換,則無法還原原字串。所以當位元組序列想變回字串,那麼位元組序列是什麼編碼格式,則轉換成字串也要用這種編碼形式,否則就會出現亂碼的情況。

通過以上五段程式碼,對程式設計中的編碼問題是不是有了一些概念。其實文字檔案本身存放就是位元組序列,而且可以是任意編碼形式的位元組序列。需要注意的是,假如我在中文機上建立一個文字檔案,這個文字檔案只能夠識別ANSI這種編碼格式的位元組序列,這裡尤其強調是建立的文字檔案,加入我從它處複製到中文機上一個文字檔案,這個文字檔案是不需要必須是ANSI編碼格式的,可以是任意編碼形式的文字檔案,當複製到中文機上的時候,可以自動完成識別。上面整段話不太好理解,只要記住,向中文機複製檔案是不需要關心它的編碼格式的,但是建立的話,只能是ANSI編碼格式下進行建立,如果你建立一個其它格式的,就會出現亂碼。

另外還需要關注一點,在Java中,我們可以看到程式碼1下表示工程下預設的編碼格式是utf-8,但是如果在另一個工程中是採用的其它編碼格式,兩個工程間的文字檔案是無法直接複製的,因為無法識別,會出現亂碼,當然,如果你直接複製文字內容的話,可以做到自動識別,這是沒有問題的。

這幾個例子就先說到這裡,在《Java IO(01)編碼問題(二)》中會更加詳細具體介紹編碼問題,包括二進位制中的一些基礎回顧,例如位運算,大小端等。

參考內容:

https://www.imooc.com/video/1832/0

https://zhidao.baidu.com/question/1637850644089866940.html

http://www.cnblogs.com/vhua/p/idea_1.html