今天想写一个小工具从一个文件中提取一些文本,代码如下:
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题public static void Main(string[] args)
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    StreamReader sr 
= new StreamReader(args[0], Encoding.Default, false1);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    sr.BaseStream.Seek(
0x00005298, SeekOrigin.Begin);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
string line = null;
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
do
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        line 
= sr.ReadLine();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        Console.WriteLine(line);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    }

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
while (sr.BaseStream.Position < 0x0000B0DA);        
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    sr.Close();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题}

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题

但是当读取到0x0000AE98时就结束了。将代码修改如下,以输出sr.BaseStream.Position;

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题public static void Main(string[] args)
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    StreamReader sr 
= new StreamReader(args[0], Encoding.Default);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    sr.BaseStream.Seek(
0x00005298, SeekOrigin.Begin);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
string line = null;
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
do
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        line 
= sr.ReadLine();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        Console.WriteLine(line 
+ sr.BaseStream.Position);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    }

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
while (sr.BaseStream.Position < 0x0000B0DA);        
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    sr.Close();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题}


发现Position是以2048为一个步幅增加的,因此明白是由于StreamReader采取了Buffer所致的。通过在.NET Framework SDK中查找发现,通过构造函数可以指定StreamReader的buffer size,但最小值是128,也就是,无法禁用StreamReader的buffer。

想到的解决方法有两个,都是首先用FileStream.Read将整个区间的数据读到一个buffer中,然后可
1)以这个buffer为基础构建一个MemoryStream,然后使用StreamReader读取。
或者2)调用Encoding.Default.GetString(),得到string,然后构建一个StringReader读取。

两种方式的代码分别如下:
1)使用MemoryStream和StreamReader

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题public static void Main(string[] args)
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    FileStream fs 
= new FileStream(args[0], FileMode.Open);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    fs.Seek(
0x00005298, SeekOrigin.Begin);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
byte[] buffer = new byte[0x0000B0DA - 0x00005298];
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    fs.Read(buffer, 
0, buffer.Length);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    fs.Close();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    StreamReader sr 
= new StreamReader(new MemoryStream(buffer), Encoding.Default);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
string line = sr.ReadLine();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
while (line != null)
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        Console.WriteLine(line);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        line 
= sr.ReadLine();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    }

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    sr.Close();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题}


2)使用Encoding.GetString和StringReader

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题public static void Main(string[] args)
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    FileStream fs 
= new FileStream(args[0], FileMode.Open);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    fs.Seek(
0x00005298, SeekOrigin.Begin);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
byte[] buffer = new byte[0x0000B0DA - 0x00005298];
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    fs.Read(buffer, 
0, buffer.Length);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    fs.Close();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    StringReader sr 
= new StringReader(Encoding.Default.GetString(buffer));
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
string line = sr.ReadLine();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    
while (line != null)
{
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        Console.WriteLine(line);
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题        line 
= sr.ReadLine();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    }

StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题    sr.Close();
StreamReader缓冲引起BaseStream.Position不能反映当前Read位置的问题}


我测试过两种方法后,得出的结论是StringReader快一点点,非常小的一点点。也许数据量大一点的情况下,会有不同的结果吧。

内部实现上,StringReader是用的string内的char遍历找出行分隔符,然后调用substring得到子串,而StreamReader则针对缓冲区的大小建立字符数组缓冲区(char[]),然后每次调用Decoder.GetChars从byte[]获取字符串数组,然后通过遍历char数组找出分隔符,最后创建一个StringBuilder,调用其Append(char[],...)方法返回子串。

相关文章:

  • 2021-11-26
  • 2021-10-31
  • 2021-11-19
  • 2022-12-23
  • 2022-02-22
  • 2021-10-18
  • 2022-12-23
猜你喜欢
  • 2021-06-27
  • 2021-11-19
  • 2021-05-26
  • 2022-12-23
  • 2021-06-19
  • 2021-07-23
  • 2022-12-23
相关资源
相似解决方案