首先,我知道我可以用不同的方式解决这个问题。我想这个问题的存在只是因为以不正确的方式使用不同的方法。但我想知道我的例子到底发生了什么。
我使用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;
}
在读取之前使用属性StreamReader.EndOfStream时,BaseStream.Read拒绝获取最后1024个字节。后来我发现信息,EndOfStream尝试读取1个字节,但实际上他读取了1024字节的性能。显然这1kb无法达到。
编辑:如果我在代码中删除 reader.EndOfStream 属性, reader.BaseStream.Read 将正常运行。这是主要的问题。
我再次理解,这个代码示例绝对是低效的。我只是想了解流如何在该示例中工作并且由于仅有错误的代码(或StreamReader.BaseStream有一些问题)而存在此问题?提前谢谢。
答案 0 :(得分:0)
不是StreamReader.BaseStream
有一些问题,但代码中存在问题。当您直接使用Stream
内的StreamReader
包裹时。
从MSDN了解StreamReader.DiscardBufferedData:
只有当内部缓冲区和BaseStream的位置不匹配时,才需要调用此方法。当您将数据读入缓冲区然后在基础流中寻找新位置时,这些位置可能会不匹配。
这意味着,在您的情况下,当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
但是,偏移和长度应该相等,我的情况长度 - 偏移= 1024(如果文件大于1kb)。也许我做错了,但是如果我使用大小小于1kb的文件,readBytes总是等于0。
因为你第一次调用while (!reader.EndOfStream)
,读者必须读取文件(这种情况是1024字节 - 读取内部缓冲区的字节)来确定文件是否结束(见两行)我上面添加的代码),在读取文件后寻找1024字节,这就是为什么length - offset = 1024
,如果你的文件小于1kb然后用这个第一次调用,它已经寻求文件结束。这是您丢失数据的地方。
第二次打电话,它不会寻求,因为你没有向读者发送任何读取请求,因此它被认为没有改变,那么它不再需要读取文件来检查是否在文件的末尾,这就是为什么第二次通话不会丢失数据。