说明:

         在《 .NET 4.0面向对象编程漫谈 》基础篇《 13.2.1 序列化与流》中,向大家介绍了如何向流中序列化一个对象。

         本篇扩充阅读将向读者介绍将字符串对象的序列化,这里面的关键是字符串应该如何编码和解码为二进制数值,从而可以把它们保存到文件流( FileStream)中,或者通过网络流( NetworkStream)将它们远程发送到另一台计算机上。

抱怨一下:

     使用CSDN的在线编辑器写文章是一个让人望而生畏的工作,当提交文档时,CSDN Web服务器经常报告“内部错误”,所以文章排版不好,诸位见谅。博客园的系统稳定些,读者可以访问http://www.cnblogs.com/bitfan/archive/2010/11/25/1887590.html 看到排版好一点的同样文章。


 ==============================================================       

1 引子

         在实际开发中,经常需要将一些字符串写入到文本文件中,或者从文本文件中读入字符串,在 .NET应用程序中,通常使用 StreamReader StreamWriter两个类完成这一工作,比如以下代码将 fileContent字串写入到 FileName文件中:

static   void  WriteFileUseStreamWriter(String fileContent, String FileName)
{
  using  (StreamWriter writer  =   new  StreamWriter(FileName))
  {
    writer.Write(fileContent);
  }
}

如果你使用 .NET基类库中相关类(比如 StreamReader或下面用到的 File类)去读取这个文件,你会发现一切如你所愿地正常运转:

WriteFileUseStreamWriter( " 中国ab " " test.txt " );
Console.WriteLine(File.ReadAllText( " test.txt " ));      // 输出:“中国ab”   
       

    由于多数情况下我们都工作在中文 Windows下,而且往往都是某个 .NET程序写,另一个 .NET程序读,所以,不少 .NET程序员可能都没注意到这其中其实存在着一个字符编码的问题,在特定的场合下,这一问题会给我们带来麻烦。

         请看图 1

漫谈.NET开发中的字符串编码

 图1 记事本支持的编码方式

         默认情况下, Windows记事本以 ANSI编码方式保存文件。如图 1所示,如果文本内容为“中国 ab ,记事本将其以 ASNI方式保存为“ test.txt”,则以下代码将“罢工”了(参看图 2):

Console.WriteLine(File.ReadAllText( " test.txt " ));

      

漫谈.NET开发中的字符串编码  

图2 汉字将显示为乱码

         图 2 所示, File.ReadAllText方法打开“ test.txt”文件时,会发现英文字符可以正常显示,但中文将显示为乱码。

2 了解字符的编码

         我们可以做个试验,使用记事本将“中国 ab”这个中英混杂的字符串以不同编码方式保存为多个“ .txt”文件,然后直接查看其二进制内容:

漫谈.NET开发中的字符串编码

 图3   比对字符编码


          图 3 展示了“中国 ab”按四种编码方式( ANSI UTF8 Unicode Unicode Big Endian )得到的不同二进制数据。

         以英文字符“ a”为例, ANSI UTF8得到的数值都是“ 61”,但 Unicode将它扩充为 2个字节 16位的二进制(“ 61 00”和“ 00 61”),所以我们又将这种编码方式称为 UTF-16

         UTF-16 又可以细分为 2种编码方式: Big Endian方式与 Little_Edian方式,这两者的唯一区别在于字节排列顺序刚好相反, Little_Edian方式将“ a”编码为“ 61 00”,而 Big Endian方式则编码为“ 00 61”。

         现在看看中文字符,“中国”两个汉字, ANSI编码为“ D6 D0 B9 FA”, 4个字节,一个汉字占两个字节,而 UTF8则编码为“ E4 B8 AD E5 9B BD”, 6个字节,一个汉字占 3个字节!这说明 UTF8是一种“变长”的编码,可能使用 1~4个字节来表示某个字符。

         另外,我们看到 UTF8 Unicode编码(不管是 Big Endian还是 Little Endian )前面都有几个标记字符,这些字符放在文本文件的开头,称为“ BOM Byte Order Mark,字节顺序标记)”指明了文本的编码方式,以下是 .NET程序中常见的字符编码方式的 BOM值:

 

 

编码

BOM

UTF-8

EF BB BF

UTF-16   big endian

FE FF

UTF-16   little endian

FF FE

UTF-32   big endian

00 00 FE FF

UTF-32   little endian

FF FE 00 00

 

 

         了解了上述基础知识,我们就可以依据 BOM值自动检测字符串的编码方式,从而正确从二进制数据流中解码,以下代码检测文本二进制数据是否采用 UTF8编码:

// 打开文件读取二进制数据
byte [] FileContents  =  File.ReadAllBytes(FilePath);
int  filelength  =  FileContents.Length;
// 检测BOM
if  (FileContents[ 0 ==   0xef   &&  FileContents[ 1 ==   0xbb &&  FileContents[ 2 ==   0xbf )
{  
   
// 按UTF8解码字符串,注意要排除掉BOM占用的3个字节。
   String content =  Encoding.UTF8.GetString( FileContents,  3 , filelength  -   3 );
   Console.WriteLine(content);
}

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-05-09
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-10-18
  • 2022-02-03
  • 2021-12-25
  • 2021-05-19
  • 2022-12-23
相关资源
相似解决方案