关于BinaryReader读取数据:在构造函数中指定编码格式

问题描述:使用BinaryReader从文件中读取数据,开始在创建BinaryReader实例的时候,未指定编码格式,结果能通过编译,但是能在执行过程中会报错如下:“未处理的异常:  System.ArgumentException: 输出字符缓冲区太小,无法包含解码后的字符,编码“Unicode (UTF-8)”的操作回退“System.Text.DecoderReplacementFallback”。”

 

解决过程:

  首先附上创建文件的代码:

ExpandedBlockStart.gif BinaryWriter
 1  using  System;
 2  using  System.IO;
 3 
 4  class  binaryReader
 5  {
 6       static   void  Main ()
 7      {
 8          FileInfo f  =   new  FileInfo( " BinFile2.dat " );
 9          BinaryWriter bw  =   new  BinaryWriter(f.OpenWrite());
10 
11          Console.WriteLine( " Base Stream is : {0} " ,bw.BaseStream);
12          
13           double  aDouble  =   1234.67 ;
14           int  anInt  =   32141 ;
15           char [] aCharArray  =  { ' A ' , ' B ' , ' C ' };
16           string  aString  =   @" teststring " ;
17 
18          bw.Write(aDouble);
19          bw.Write(anInt);
20          bw.Write(aCharArray);
21          bw.Write(aString);
22          bw.Close();
23 
24      }
25  }

  然后附上BinaryReader测试代码:

ExpandedBlockStart.gif BinaryReader
 1  using  System;
 2  using  System.IO;
 3  using  System.Text;
 4 
 5  class  binaryReader
 6  {
 7       static   void  Main()
 8      {                
 9          FileInfo f2  =   new  FileInfo( " BinFile2.dat " );
10 
11                  BinaryReader br  =   new  BinaryReader(f2.OpenRead());
12           // BinaryReader br = new BinaryReader(f2.OpenRead(),Encoding.Default);
13 
14           int  temp  =   0 ;
15          
16           while  (br.PeekChar()  !=   - 1 )
17          
18          {
19              Console.Write( " {0,7:x} " ,br.ReadByte());
20 
21               if  ( ++ temp  ==   4 )
22              {
23                  Console.WriteLine();
24                  temp  =   0 ;
25              }
26              
27          }
28          Console.WriteLine();
29      }
30  }

  还有错误提示:

  由上,之输出第一字符的16进制编码,剩下的就开始报错。但是觉得“字符缓冲区太小”是个很诡异的错误,然后就在网上搜了下,看看别人是怎么做的。

  第一次,在CSDN上看见有人给出了解决的方案,如题目所言,在创建BinaryReader实例的时候,指定其编码方式,就像上面代码中注释掉的那一行那样,就能够解决问题,将所有字符的16进制编码正常输出。

  这样,问题首先集中到编码上。默认的编码方式有问题,必须指定,才能避免错误。那什么样的编码是可行的,什么样的编码有问题?在Encoding里面,枚举了六种编码方式:UTF7、UTF8、Unicode、BigEndianUnicode、UTF32和Default。要说的是这里的Default是指:System.Text.DBCSCodePageEncoding。接下来,我做了一个测试,枚举每一种编码方式,在上面的代码中挨个试一遍。结果发现,在我写的那个BinFile2.dat测试文件上,除了UTF-8运行失败外,其他的每种方式都是成功的(此处截图省略)。那么,就可以推断,不带编码指定的BinaryReader的构造函数默认使用的是UTF-8的编码,而这样在读取过程中试有问题的。

  现在,至少知道用该用那种编码了。

  问题再进一步,在函数块内部,在读取文件的过程中,是哪个函数调用对编码有“苛刻”的要求?在上面的函数块中,只包含两个方法的调用,一个是while语句中的PeekChar(),一个是Console.WriteLine()。我觉得后者的可能性不大,于是做了如下的测试:

ExpandedBlockStart.gif BinaryReader2
 1  using  System;
 2  using  System.IO;
 3  using  System.Text;
 4 
 5  class  binaryReader
 6  {
 7       static   void  Main()
 8      {                
 9          FileInfo f2  =   new  FileInfo( " BinFile2.dat " );
10 
11          BinaryReader br  =   new  BinaryReader(f2.OpenRead(),Encoding.Default);
12           int  temp  =   0 ;
13           int  count = 20;
14           while  (count > 0 )
15          {
16              Console.Write( " {0,7:x} " ,br.ReadByte());
17 
18               if  ( ++ temp  ==   4 )
19              {
20                  Console.WriteLine();
21                  temp  =   0 ;
22              }
23              
24                          count -- ;
25          }
26          Console.WriteLine();
27      }
28  }

  结果,除了没能完全输出字符之外,运行正常,于是,问题集中在了PeekChar()上面。上面用它来判断文件的边界,MSDN中描述“下一个可用的字符,或者,如果没有可用字符或者流不支持查找时为 -1。”也就是说,PeekChar()在判断是否到边界的过程中,有一个预读的过程,结合上面的编码的问题,可以猜测,在它预读的时候由于编码的不合适,导致在该方法内部的缓冲区的溢出。

  又在网上找到一文《不要使用PeekChar()判断EOF》,文中只是说不要用PeekChar来判断EOF,而是使用判断条件 ( br.BaseStream.Position < br.BaseStream.Length),但是并没有给出详细的理由。

 

   而后,又发现了老外也在讨论这个问题:http://bytes.com/topic/visual-basic-net/answers/349779-binaryreader-peekchar-argumentexception-conversion-buffer-overflow

  ……

  继续深入下去,有两个点要解决:1、UTF-8编码的问题;2、PeekChar的工作详细细节。

总结:通过以上的一系列做法,对BinaryReader的使用有了一些粗浅的了解,在使用过程中,能够合理利用,避开容易出错的地方,但是,根本的问题还未能真正解决。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

      更深入的明日再续。

 

转载于:https://www.cnblogs.com/YFYkuner/archive/2010/03/22/1691981.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值