使用EndOfStream属性后出现StreamReader.BaseStream问题

时间:2016-02-27 10:01:20

标签: c# stream filestream streamreader

首先,我知道我可以用不同的方式解决这个问题。我想这个问题的存在只是因为以不正确的方式使用不同的方法。但我想知道我的例子到底发生了什么。

我使用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有一些问题)而存在此问题?提前谢谢。

1 个答案:

答案 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然后用这个第一次调用,它已经寻求文件结束。这是您丢失数据的地方。

第二次打电话,它不会寻求,因为你没有向读者发送任何读取请求,因此它被认为没有改变,那么它不再需要读取文件来检查是否在文件的末尾,这就是为什么第二次通话不会丢失数据。