Encoding Gossip: Unicode 與 UTF
来源:互联网 发布:matlab 矩阵拼接 编辑:程序博客网 时间:2024/05/16 10:05
http://caterpillar.onlyfun.net/Gossip/Encoding/UnicodeUTF.html
在你按下「取消」後,會出現「另存新檔」的對話框,在右下會有個「編碼」選項,下拉的話,會有Unicode、Unicode big endian與UTF-8三個選項。
Unicode是由The UnicodeConsortium非營利組織所主導的編碼標準,給予每個字元唯一的編碼,在表達時,於「U+」之後接著一組十六進位數字來表示編碼數字,如果使用四個十六進位制數字,可以表達六萬多個字元,如果使用五或六個十六進位制,則可以表達更多的字元。
Unicode是指編碼方式,一個文字的Unicode編碼是固定的,但如何用位元組來表達則視目的而有不同的實作方式,Unicode的實作方式就稱為Unicode/UCS Transformation Format,簡稱UTF。
如果你直接將方才的範例選擇「Unicode」儲存,用十六進位檢視,你會看到:
「犇」這個字的Unicode編碼是U+7287,對於Windows的記事本若選擇使用「Unicode」儲存,則使用兩個位元組來儲存,Windows的記事本選擇「Unicode」選項時,實際上採用UCS-2/UTF-16 儲存,一開頭的兩個位元組(ff fe)是用來識別檔案採用的位元組順序,稱為BOM(byte order mark),之後使用兩個位元組來儲存每個Unicode字元。
要注意的是,「犇」這個字的Unicode編碼是U+7287,實際儲存時的位元組卻是87、72,也就是說,Windows記事本選擇「Unicode」儲存兩個以上位元組的資料時,是先存低位元組,再存高位元組,這樣的儲存方式,是採Little Endian 的方式,也就是Windows記事本選擇「Unicode」時,實際上採用的是UCS-2/UTF-16 Little Endian。
Unicode指定BOM編碼為U+FEFF。如果讀取檔案開頭的BOM順序是0xfeff,表示檔案採用Big Endian,如果讀取檔案開頭的BOM順序是0xfffe,表示檔案採用Little Endian。
如果使用Windows記事本儲存時的選項是「Unicode big endian」,同樣儲存「犇」,結果會如下:
可以看到,用來表示為Unicode檔案的兩個位元組為fe、ff,與先前的ff、fe相反,而「犇」這個字現在儲存為72、87,與先前的87、72也是相反。如果儲存兩個以上位元組資料時,採先存高位元,再存低位元方式,則這樣的儲存方式,是採Big Endian 的方式。
這會有什麼影響?如果你使用以下的Java程式來讀取一個存有「這T是e個s測t試」的文字檔案,而文字檔案採Windows記事本中的「Unicode」選項儲存,那麼你會得到亂碼:
import java.io.*;public class Main { public static void main(String[] args) throws Exception { FileInputStream in = new FileInputStream(args[0]); byte[] data = new byte[2]; while(in.read(data) != -1) { int hex = ((data[0] << 8) | (data[1] & 0xFF)) & 0XFFFF; System.out.printf("%h ", hex); System.out.println(new String(data, "UTF-16")); } in.close(); }}
C:\workspace>java Main sample.txt
fffe
1990 ?
5400 ?
2f66 ?
6500 攀
b50 ?
7300 猀
2c6e ?
7400 琀
668a 暊
如果存有「這T是e個s測t試」的文字檔案,是使用Windows記事本「Unicode big endian」選項儲存,也就是採UCS-2/UTF-16 Big Endian,則以上程式可以得到正確的文字顯示:
C:\workspace>java Main sample.txt
feff
9019 這
54 T
662f 是
65 e
500b 個
73 s
6e2c 測
74 t
8a66 試
這是因為JVM本身是採Big Endian的方式來處理位元組,對於一個文字檔案採Windows記事本中的「Unicode」選項儲存,則是採Little Endian,用以上的程式讀取當然會是亂碼,如果要正確讀取Windows記事本中的「Unicode」選項儲存的文字檔案,方法之一是在Java中要自行調換位元組順序:
import java.io.*;public class Main { public static void main(String[] args) throws Exception { FileInputStream in = new FileInputStream(args[0]); byte[] data = new byte[2]; byte[] bigEndian = new byte[2]; while(in.read(data) != -1) { int hex = ((data[0] << 8) | (data[1] & 0xFF)) & 0XFFFF; System.out.printf("%h ", hex); bigEndian[0] = data[1]; bigEndian[1] = data[0]; System.out.println(new String(bigEndian, "UTF-16")); } in.close(); }}
或者是指定使用UTF-16LE,例如:
import java.io.*;public class Main { public static void main(String[] args) throws Exception { FileInputStream in = new FileInputStream(args[0]); byte[] data = new byte[2]; while(in.read(data) != -1) { int hex = ((data[0] << 8) | (data[1] & 0xFF)) & 0XFFFF; System.out.printf("%h ", hex); System.out.println(new String(data, "UTF-16LE")); } in.close(); }}
這兩個程式,都可以正確讀取,例如:
C:\workspace>java Main sample.txt
fffe
1990 這
5400 T
2f66 是
6500 e
b50 個
7300 s
2c6e 測
7400 t
668a 試
有關於UTF-8,則在 下一篇 再繼續說明....XD
- Encoding Gossip: Unicode 與 UTF
- Encoding Gossip: JVM 預設編碼
- 【Encoding】ANSI,ASCII,Unicode,utf-8的区别与联系
- The file “city.txt” couldn’t be opened using text encoding Unicode (UTF-8)
- utf&unicode
- # encoding: utf-8
- c#字符编码,System.Text.Encoding类,字符编码大全:如Unicode编码、GB18030、UTF-8,UTF-7,GB2312,ASCII,UTF32,Big5
- [c#] set utf-8 encoding
- 【Encoding】UTF-8编码规则
- scrapy:LookupError: unknown encoding: 'unicode'
- Unicode UTF-8 UTF-16
- UNICODE,UTF-8,UTF-16
- Unicode(UTF-8, UTF-16)
- Unicode(UTF-8, UTF-16)
- Encoding Gossip: 哪來的純文字檔?
- Unicode,UTF-8,UTF-16,UTF-32
- unicode,utf-8,utf-16,utf-32
- UTF-8和Unicode
- C++ 模板为什么不能分离编译
- group by后的汇总结果,如何去和总和做百分比
- #define new DEBUG_NEW
- php优化的几点
- 论学习与娱乐
- Encoding Gossip: Unicode 與 UTF
- JSP指令、JSP九大隐式对象、out隐式对象详细
- 关于EL表达式
- smarty 相关知识
- 编译framework的正确方式
- MFC CreateProcess创建可控制窗口的进程
- 程序员应当如何保持优秀
- Sizeof与Strlen的区别与联系
- Android init.rc介绍