StreamReader.BaseStream 使用 EndOfStream 后出现问题 属性
StreamReader.BaseStream issue after using EndOfStream property
首先我明白我可以用不同的方式解决这个问题。我想这个问题的存在只是因为以不正确的方式使用了不同的方法。但我想知道在我的示例中究竟发生了什么。
我正在使用 StreamReader 读取文件。为了从中获取字节,我决定使用 BaseStream.Read:
int length = (int)reader.BaseStream.Length;
byte[] file = new byte[length];
while(!reader.EndOfStream)
{
int readBytes = reader.BaseStream.Read(file, 0,
(length-offset)>bufferSize?bufferSize:(length - offset));
for (int i = 0; i<readBytes; i++)
{
...
}
offset += readBytes;
}
BaseStream.Read 在读取前使用 属性 StreamReader.EndOfStream 时拒绝获取最后 1024 个字节。后来查到资料,说EndOfStream试图读取1个字节,但实际上由于性能原因他读取了1024个字节。显然这 1kb 变得不可能达到。
编辑: 如果我在代码中删除 reader.EndOfStream 属性,reader.BaseStream.Read 将正常工作。这是问题的重点。
同样,我明白,这个代码示例绝对是低效的。我只是想了解流在那个例子中是如何工作的,这个问题是否仅仅因为错误的代码而存在(或者 StreamReader.BaseStream 有一些问题)?提前致谢。
这不是 StreamReader.BaseStream
有一些问题,而是您的代码中的问题。当您直接使用包裹在 StreamReader
.
中的 Stream
时
来自 MSDN 关于 StreamReader.DiscardBufferedData:
You need to call this method only when the position of the internal buffer and the BaseStream do not match. These positions can become mismatched when you read data into the buffer and then seek a new position in the underlying stream.
也就是说,在你的情况下,当Stream
已经到达结束位置时,StreamReader
内部缓冲区的位置仍然是你之前的值直接读取底层流,因此 reader.EndOfStream
仍然 = false
。这就是为什么你无法完成循环的原因。
编辑:
我觉得你漏掉了什么,我给你这个代码来证明文件成功到达结尾。 运行 它,您会看到您的应用重复说:我在文件末尾!
static void Main()
{
using (StreamReader reader = new StreamReader(@"yourFile"))
{
int offset = 0;
int bufferSize = 102400;
int length = (int)reader.BaseStream.Length;
byte[] file = new byte[length];
while (!reader.EndOfStream)
{
// Add this line:
Console.WriteLine(reader.BaseStream.Position);
Console.ReadLine();
int readBytes = reader.BaseStream.Read(file, 0,
(length - offset) > bufferSize ? bufferSize : (length - offset));
string str = Encoding.UTF8.GetString(file, 0, readBytes);
offset += readBytes;
if (reader.BaseStream.Position == length)
{
Console.WriteLine("I'm at the end of the file! Current Tickcount: " + Environment.TickCount);
Thread.Sleep(100);
}
}
}
}
编辑 2
But still , offset and length should be equal, im my case length - offset = 1024 (in case of files that bigger than 1kb). Maybe I'm doing something wrong, but if I use files with size less than 1kb, readBytes always equals 0.
那是因为你第一次调用 while (!reader.EndOfStream)
,reader 必须读取文件(本例为 1024 字节 - 读取字节到内部缓冲区)以确定文件是否结束 (见我在上面添加的两行代码),在它读取文件后寻找 1024 字节,这就是为什么 length - offset = 1024
,如果你的文件小于 1kb 那么第一次调用,它已经寻找到文件末尾。这是您丢失数据的地方。
第二次调用它,它不寻找,因为你没有向reader发送任何读取请求,所以它认为不变,那么它不需要再次读取文件来检查是否在文件末尾,这就是为什么第二次调用不会丢失数据的原因。
首先我明白我可以用不同的方式解决这个问题。我想这个问题的存在只是因为以不正确的方式使用了不同的方法。但我想知道在我的示例中究竟发生了什么。
我正在使用 StreamReader 读取文件。为了从中获取字节,我决定使用 BaseStream.Read:
int length = (int)reader.BaseStream.Length;
byte[] file = new byte[length];
while(!reader.EndOfStream)
{
int readBytes = reader.BaseStream.Read(file, 0,
(length-offset)>bufferSize?bufferSize:(length - offset));
for (int i = 0; i<readBytes; i++)
{
...
}
offset += readBytes;
}
BaseStream.Read 在读取前使用 属性 StreamReader.EndOfStream 时拒绝获取最后 1024 个字节。后来查到资料,说EndOfStream试图读取1个字节,但实际上由于性能原因他读取了1024个字节。显然这 1kb 变得不可能达到。
编辑: 如果我在代码中删除 reader.EndOfStream 属性,reader.BaseStream.Read 将正常工作。这是问题的重点。
同样,我明白,这个代码示例绝对是低效的。我只是想了解流在那个例子中是如何工作的,这个问题是否仅仅因为错误的代码而存在(或者 StreamReader.BaseStream 有一些问题)?提前致谢。
这不是 StreamReader.BaseStream
有一些问题,而是您的代码中的问题。当您直接使用包裹在 StreamReader
.
Stream
时
来自 MSDN 关于 StreamReader.DiscardBufferedData:
You need to call this method only when the position of the internal buffer and the BaseStream do not match. These positions can become mismatched when you read data into the buffer and then seek a new position in the underlying stream.
也就是说,在你的情况下,当Stream
已经到达结束位置时,StreamReader
内部缓冲区的位置仍然是你之前的值直接读取底层流,因此 reader.EndOfStream
仍然 = false
。这就是为什么你无法完成循环的原因。
编辑:
我觉得你漏掉了什么,我给你这个代码来证明文件成功到达结尾。 运行 它,您会看到您的应用重复说:我在文件末尾!
static void Main()
{
using (StreamReader reader = new StreamReader(@"yourFile"))
{
int offset = 0;
int bufferSize = 102400;
int length = (int)reader.BaseStream.Length;
byte[] file = new byte[length];
while (!reader.EndOfStream)
{
// Add this line:
Console.WriteLine(reader.BaseStream.Position);
Console.ReadLine();
int readBytes = reader.BaseStream.Read(file, 0,
(length - offset) > bufferSize ? bufferSize : (length - offset));
string str = Encoding.UTF8.GetString(file, 0, readBytes);
offset += readBytes;
if (reader.BaseStream.Position == length)
{
Console.WriteLine("I'm at the end of the file! Current Tickcount: " + Environment.TickCount);
Thread.Sleep(100);
}
}
}
}
编辑 2
But still , offset and length should be equal, im my case length - offset = 1024 (in case of files that bigger than 1kb). Maybe I'm doing something wrong, but if I use files with size less than 1kb, readBytes always equals 0.
那是因为你第一次调用 while (!reader.EndOfStream)
,reader 必须读取文件(本例为 1024 字节 - 读取字节到内部缓冲区)以确定文件是否结束 (见我在上面添加的两行代码),在它读取文件后寻找 1024 字节,这就是为什么 length - offset = 1024
,如果你的文件小于 1kb 那么第一次调用,它已经寻找到文件末尾。这是您丢失数据的地方。
第二次调用它,它不寻找,因为你没有向reader发送任何读取请求,所以它认为不变,那么它不需要再次读取文件来检查是否在文件末尾,这就是为什么第二次调用不会丢失数据的原因。