今天想写一个小工具从一个文件中提取一些文本,代码如下:
public static void Main(string[] args)


{
StreamReader sr = new StreamReader(args[0], Encoding.Default, false, 1);
sr.BaseStream.Seek(0x00005298, SeekOrigin.Begin);
string line = null;
do

{
line = sr.ReadLine();
Console.WriteLine(line);
}
while (sr.BaseStream.Position < 0x0000B0DA);
sr.Close();
}
但是当读取到0x0000AE98时就结束了。将代码修改如下,以输出sr.BaseStream.Position;
public static void Main(string[] args)


{
StreamReader sr = new StreamReader(args[0], Encoding.Default);
sr.BaseStream.Seek(0x00005298, SeekOrigin.Begin);
string line = null;
do

{
line = sr.ReadLine();
Console.WriteLine(line + sr.BaseStream.Position);
}
while (sr.BaseStream.Position < 0x0000B0DA);
sr.Close();
}
发现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
public static void Main(string[] args)


{
FileStream fs = new FileStream(args[0], FileMode.Open);
fs.Seek(0x00005298, SeekOrigin.Begin);
byte[] buffer = new byte[0x0000B0DA - 0x00005298];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
StreamReader sr = new StreamReader(new MemoryStream(buffer), Encoding.Default);
string line = sr.ReadLine();
while (line != null)

{
Console.WriteLine(line);
line = sr.ReadLine();
}
sr.Close();
}
2)使用Encoding.GetString和StringReader
public static void Main(string[] args)


{
FileStream fs = new FileStream(args[0], FileMode.Open);
fs.Seek(0x00005298, SeekOrigin.Begin);
byte[] buffer = new byte[0x0000B0DA - 0x00005298];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
StringReader sr = new StringReader(Encoding.Default.GetString(buffer));
string line = sr.ReadLine();
while (line != null)

{
Console.WriteLine(line);
line = sr.ReadLine();
}
sr.Close();
}
我测试过两种方法后,得出的结论是StringReader快一点点,非常小的一点点。也许数据量大一点的情况下,会有不同的结果吧。
内部实现上,StringReader是用的string内的char遍历找出行分隔符,然后调用substring得到子串,而StreamReader则针对缓冲区的大小建立字符数组缓冲区(char[]),然后每次调用Decoder.GetChars从byte[]获取字符串数组,然后通过遍历char数组找出分隔符,最后创建一个StringBuilder,调用其Append(char[],...)方法返回子串。