犬者
“说了你又不听,听又不懂,懂又不做,做又做错,错又不认,认又不改,改又不服,不服也不说,那叫我怎么办?!”

【电脑】动态修改.Net StreamReader Encoding编码

在.Net framework中StreamReader的使用encoding必须在构造器中指定,而且中途完全不可以更改。

在一般的情况下,这不会造成什么问题。一般若是从硬盘读取文件,单一文件内的编码一般都是统一的。即便是发现读错,亦可以关闭StreamReader,重启使用新的编码读取。

偏偏偶最近遇到了需要修改编码的需求,而且,我的程序没有关闭重读的机会。因为偶使用的StreamReader的BaseStream是一个Network Stream,我不可以关闭它……但是Network Stream传过来的东西很可能包涵不同的编码……GB2312,Big5,UTF8,ISO-8859-1等等……虽然是先得到编码信息,然后再读具体内容,但是,一开始使用的Stream Reader编码一旦错了,读出来的东西便再也无法恢复……会丢字之类的……

我也不可以在获得编码信息之后,重新建立一个新的Stream Reader,因为具体内容已经被原来的Stream Reader给缓冲掉了……

唯一的解决方法,便是自己实现一个可以改变CurrentEncoding属性的Stream Reader了……

全部从头写起非常不实际,偶是先当了mono源码,从mono的Stream Reader实现代码做修改。

代码就不贴了,只讲原理。

Stream Reader其实很简单,它内部有两个Buffer,一个是input buffer,一个是decoded buffer,前者用于缓存从base stream读过来的原始数据,后者用于缓存根据原始数据解码出来后的东西……只要看明白mono的实现中ReadBuffer这个方法,要动态修改CurrentEncoding也就不是太难了……

我需要处理的网络协议是一个行协议……偶在程序中只调用了StreamReader的Readline方法,而完全没有使用Read的两个方法,这也使得偶动态修改编码容易了许多……

偶的做法是每次调用Readline的时候,不仅移动decoded buffer的游标(pos),同时也移动input buffer一个新的游标(pos_input),做法很简单,Readline方法需要调用FindNextEOL移动游标查找换行符号……我在FindNextEOL方法添加多一行:
  int FindNextEOL ()
  {
   FindNextInputEOL();
   ....

而FindNextInputEOL这个新的函数,完全是FindNextEOL的翻版,只是前者处理input buffer,而后者处理decoded buffer……

如此一来,我便可以知道每次Readline之后,input buffer中还没有被上层读到的原始数据有哪些了……

然后,再把CurrentEncoding属性添加Set的方法:
set
   {
    encoding=value;
    decoder = encoding.GetDecoder();
    decoded_count = pos + decoder.GetChars (input_buffer, pos_input, cbEncoded , pos_input, decoded_buffer, pos);
   }

设定新编码时,程序便根据input buffer的游标(pos_input)把没有被读到的原始数据重新decode一次,并且替换掉decoded buffer中的内容。

然后,事情就搞定了……甚至不需要对Readline方法做任何修改……除了把cbEncoded这个变量放到全局里面外……

但是,偶这个修改使得Read的两个方法变得完全不可以用……一旦调用了……便会使得input buffer与decoded buffer里面两个游标不同步……这里有完整的代码,还望有大侠可以帮忙把Read的两个方法也给搞定了…… 先谢过……

42999|.net|编码
问天 @9/5/2006 11:11:27 PM
View blogs in this category:电脑


Hikey 在 5/1/2007 5:09:53 PM 说:

作者真是强人...
我遇到的问题和您完全一样,至今也没有解决好。没想到这个问题终究必须要这样解决才可以...

本来想StreamReader自己可以在文件头中查找字节顺序标记
谁想到网络中的stream压根没那个标记。
我是在asp.net中使用的,使用您这段代码资源占用绝对是个大问题。
我发现 System.Xml.XmlDocument.Load()可以自动识别stream的编码,然后我用Reflector去找他是怎么实现的,但是找了很久也没有找到。

哎...真希望能找个简单点的实现
a79v 在 9/11/2006 8:54:34 AM 说:

哈哈,看懂意思而已。
GriGri 在 9/6/2006 12:35:51 AM 说:

我在头大的时候看这种内容…… 完全是折磨自己。
但是,WW的Blog还是要支持的……

Please leave your comment here

 
  名字:
  主页:
  内容:
 

   


Navigation
Blogwind
犬者首页
Contact


个人档案


“说了你又不听,听又不懂,懂又不做,做又做错,错又不认,认又不改,改又不服,不服也不说,那叫我怎么办?!”



Categories
死结(27)
电脑(169)
心情(175)
天影(25)
乱弹(204)
博客(78)
音乐(18)
饕餮(30)
读书(19)
电影(26)
网摘(5)
希望(30)
汕头(10)
经济(5)
苹果(19)
跋涉(3)



Archive
2008年7月
2008年6月
2008年5月
2008年4月
2008年3月
2008年2月
2008年1月
2007年12月
2007年11月
2007年10月
2007年9月
2007年8月
2007年7月
2007年6月
2007年5月
2007年4月
2007年3月
2007年2月
2007年1月
2006年12月
2006年11月
2006年10月
2006年9月
2006年8月
2006年7月
2006年6月
2006年5月
2006年4月
2006年3月
2006年2月
2006年1月
2005年12月
2005年11月
2005年10月
2005年9月
2005年8月
2005年7月
2005年6月
2005年5月
2005年4月
2005年3月
2005年2月
2005年1月
2004年12月
2004年11月
2004年10月
2004年9月
2004年8月
2004年7月
2004年6月
2004年5月
2004年4月
2004年3月
2004年2月
2004年1月
2003年12月



My Links
bloglines
时尚摄影师奇科的博客
我们的漫画
颜如玉
最爱卫斯理

RSS 2.0

Username:
Password:
 Remember me