Unicode,UTF-8,GB2312編碼的識別
在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字元,它的編碼是FEFF。而FFFE在UCS中是不存在的字元,所以不應該出現在實際傳輸中。UCS規範建議我們在傳輸位元組流前,先傳輸字元"ZERO WIDTH NO-BREAK SPACE"。
這樣如果接收者收到FEFF,就表明這個位元組流是Big-Endian的;如果收到FFFE,就表明這個位元組流是Little-Endian的。因此字元"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來表明位元組順序,但可以用BOM來表明編碼方式。字元"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開頭的位元組流,就知道這是UTF-8編碼了。
Unicode:FF FE
Unicode big_endian:EF FF
UTF-8: EF BB BF
GB2312是高位在前,Big_endian
所以現在我們來做個測試就可以很清楚地對以上的東東進行驗證了。
1.用notepad輸入"漢A"這2個字元﹐然後分別儲存成ANSI,Unicode,Unicode-big-endian和UTF-8,名字分別取為ansi.txt,unicode.txt,unicode_b.txt,utf8.txt,並且放在c盤根目錄下
2.用以下程式進行驗證
using System;
using System.Collections;
using System.IO;
public class MyClass
{
private static void writefile(string path)
{
FileStream fs = null;
try{
fs = new FileStream(path,FileMode.Open);
byte[] bs = new byte[fs.Length];
fs.Read(bs,0,bs.Length);
WL(BitConverter.ToString(bs));
SixTTwo(BitConverter.ToString(bs));
}
catch(Exception ex)
{
WL(ex.ToString());
}
finally
{
if(fs!=null)
fs.Close();
}
}
public static void Main()
{
string path;
WL("ANSI檔案格式的位元組流﹕");
path = "c://ansi.txt";
writefile(path);
WL("Unicode檔案格式的位元組流﹕");
path = "c://unicode.txt";
writefile(path);
WL("Unicode-big-endian檔案格式的位元組流﹕");
path = "c://unicode_b.txt";
writefile(path);
WL("utf-8檔案格式的位元組流﹕");
path = "c://utf8.txt";
writefile(path);
RL();
}
public static void SixTTwo(string sixstr)
{
string[] tmp = sixstr.Split(new char[]{'-'});
foreach(string s in tmp)
{
Console.Write(Convert.ToString(Convert.ToByte(s,16),2).PadLeft(8,'0')+ "
");
}
WL("");
}
private static void WL(string text, params object[] args)
{
Console.WriteLine(text, args);
}
private static void RL()
{
Console.ReadLine();
}
private static void Break()
{
System.Diagnostics.Debugger.Break();
}
}
3.以下是輸出格式﹕
ANSI檔案格式的位元組流﹕
BA-BA-41
10111010 10111010 01000001
Unicode檔案格式的位元組流﹕
FF-FE-49-6C-41-00
11111111 11111110 01001001 01101100 01000001 00000000
Unicode-big-endian檔案格式的位元組流﹕
FE-FF-6C-49-00-41
11111110 11111111 01101100 01001001 00000000 01000001
utf-8檔案格式的位元組流﹕
EF-BB-BF-E6-B1-89-41
11101111 10111011 10111111 11100110 10110001 10001001 01000001
從以上結果可以很容易的看到BABA正是"漢"字的gb2312編碼﹐當然我的作業系統是繁體的﹐如果我直接雙擊開啟﹐則可以看到"犖A"﹐這是亂碼﹐因為我的系統baba查的是big5﹐而baba的big5碼正是"犖"
然而還有其它很多程式﹐像IE呀,它可以使用meta標籤來識別檔案的編碼,xml也是可以通過encoding屬性來說明檔案的編碼的﹐所以這些程式的識別方法和普通的又有些不同罷了。
同樣﹐寫一個文字檔時﹐先寫入這些標記符﹐則也會協助notepad識別這些檔案的編碼(當然.net專門提供了一些類別﹐如StreamWriter﹐可以直接存成某種編碼的格式)。
至於各種encoding之間的轉換﹐我想也不必多說了﹐通過Encoding類的Convert,GetBytes和GetString方法是很容易進行轉換的。