2011-06-11 152 views
2

Hallo,我注意到当我使用UTF-8编码(无BOM)保存文本文件时,我可以在C#上使用UTF-16编码完美地读取它。现在这让我有点困惑,因为UTF-8只使用8位,对吧?而utf-16对每个角色都有16位。需要帮助了解UTF编码

现在想象一下,我在这个文件中有字符串“ab”写为UTF-8,那么在那里有一个字节用于字母“a”&另一个用于“b”。

好的,但是如何在使用UTF-16字符集时读取这个UTF-8文件?我看到它的方式,在读取文件时,“ab”的两个字节将被误认为只有一个字符包含两个字节。由于UTF-16需要这2个字节。

这是我如何读它(t.txt被编码为UTF-8):

using(StreamReader sr = new StreamReader(File.OpenRead("t.txt"), Encoding.GetEncoding("utf-16"))) 
{ 
    Console.Write(sr.ReadToEnd()); 
    Console.ReadKey(); 
} 
+3

UTF-8使用8位,当你处理的是英语 - 但如果你是在处理与其他语言的UTF-8可能是16,24,或甚至更多位。 – Sai 2011-06-11 04:27:56

+0

UTF-16需要2或4个字节。 – tchrist 2011-06-11 15:14:04

+0

@Sai,哦,我认为utf-8总是8位长,当使用16位时,它将被称为utf-16。所以我可以有16位,仍然使用utf-8而不是utf-16? – Delta 2011-06-11 15:48:21

回答

5

退房http://www.joelonsoftware.com/articles/Unicode.html,它会回答你所有的Unicode问题

+0

好文章,他说utf-8可以存储任何代码点,而其他编码如iso-8859-1,windows-1252等只是一些。现在我想知道为什么不是每个人都使用utf-8。 – Delta 2011-06-11 05:11:09

+0

大多数较新的浏览器建议使用UTF-8在网页上使用。至于其他应用程序,我认为其采用的障碍是每个字符的可变长度。与固定长度编码不同,使用'offset = n * encodingLength'不能简单地到达第n个字符。 – 2011-06-11 05:30:29

+0

@Devendra:那么你最好使用UTF-32,因为UTF-16没有那个属性。正如此评论所表明的,任何认为他们可以使用简单索引到UTF-16来获得ᵗʰ字符的人都有严重错误。网页使用UTF-8有很多很好的理由。有些在[这个答案](http://stackoverflow.com/questions/6162484/why-does-modern-perl-avoid-utf-8-by-default/6163129#6163129)的部分。 – tchrist 2011-06-11 15:17:05

1

The '8' means it uses 8-bit blocks to represent a character.这并不意味着每个字符占用一个固定的8位。每个字符块的数量从1到4不等(尽管字符长度最多可达6个字节)。

试试这个简单的测试,

  • 创建一个文本文件(比如在记事本++)与UTF8无BOM编码
  • 阅读文本文件File.ReadAllBytes()(因为你已经在你的代码中完成)。 byte[] utf8 = File.ReadAllBytes(@"E:\SavedUTF8.txt");
  • 检查每个字符所占的字节数。
  • 现在尝试使用编码为ANSI byte[] ansi = File.ReadAllBytes(@"E:\SavedANSI.txt");的文件
  • 比较两个编码的每个字符的字节数。

注意,File.ReadAllBytes()尝试基于字节顺序标记的存在自动检测文件的编码。编码格式UTF-8和UTF-32(包括big-endian和little-endian)都可以被检测到。


有趣的结果
SavedUTF8.txt包含字符

  • a:字节的字节数组中总数= 1 1 byte per character
  • ©(UTF + 00A9)(ALT + 0169):字节数在字节数组中= 2 2 bytes per character
  • :(UTF + E0A080)(Alt + 14721152)字节中的字节数ar ray = 3 3 bytes per character

ANSI编码总是需要8位(即,在上面的示例中,无论文件中的字符如何,字节数组的大小始终为1)。正如@tchrist指出的那样,UTF16每个字符需要2或4个字节(而不是每个字符固定的2个字节)。


编码表(从here
以下的字节序列来表示一个字符。所用的序列依赖于字符的Unicode数:

U-00000000 – U-0000007F: 0xxxxxxx 
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx 
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 

XXX比特位置中填充有以二进制表示的字符代码号的比特。最右边的x位是最不重要的位。只能使用可能表示字符代码号的最短可能的多字节序列。请注意,在多字节序列中,第一个字节中前导1位的数量与整个序列中的字节数量相同。


确定字符的大小

表示一个非ASCII字符的多字节序列的第一个字节总是在范围将0xC0到0xfd并且它指示多少字节遵循此字符。

这意味着,对于一个2字节字符(110)的前导比特是大于3个字节的字符(1110)的前导比特不同。这些前导位可以用来唯一标识一个字符需要的字节数。


更多信息

+0

是的,所以当charcode大于127等时,utf-8使用2个字节。这让我很好奇你怎么能知道下一个字符何时要去使用1个,2个,3个或4个字节。谢谢! – Delta 2011-06-11 05:14:01

+0

我已经更新了答案,以澄清字符字节大小的计算。顺便说一句,人们不需要知道下一个字符的大小。一旦指针达到下一个字符的位序列,就会计算大小。 – 2011-06-11 05:26:48

+0

**这个答案是错误的!** UTF-16是可变宽度,使用16位代码单元,正如UTF-8是可变宽度,使用8位代码单元。这个陈述是谎言:'同样,UTF16将总是消耗每个字符16位(它是固定的长度,与UTF8中的可变长度相比)' – tchrist 2011-06-11 15:13:29