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

本文关键字:StreamReader BaseStream 问题 EndOfStream 属性 使用 | 更新日期: 2023-09-27 18:36:25

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

我正在使用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 拒绝获取最后 1024 个字节,因为在读取之前使用了属性 StreamReader.EndOfStream。后来我发现了一个信息,EndOfStream 试图读取 1 个字节,但实际上由于性能,他读取了 1024 个字节。显然,这个 1kb 变得无法到达。

编辑:如果我删除阅读器。代码中的 EndOfStream 属性,读取器。BaseStream.Read 将正常工作。这是问题的主要问题。

同样,我知道,这个代码示例绝对是低效的。我只是想了解流在该示例中的工作原理,以及此问题是否仅因为错误代码而存在(或 StreamReader.BaseStream 有一些问题)?提前谢谢。

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

它不是StreamReader.BaseStream有一些问题,而是你的代码中的问题。当您直接使用包裹在StreamReader内的Stream工作时。

来自 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

但是,偏移量和长度仍然应该相等,我的情况长度 - offset = 1024(如果文件大于 1kb)。也许我做错了什么,但是如果我使用大小小于 1kb 的文件,readBytes 总是等于 0。

那因为你第一次调用while (!reader.EndOfStream),读卡器必须读取文件(在这种情况下是1024字节 - 将字节读取到内部缓冲区)以确定文件是否结束(请参阅我上面添加的两行代码),在它读取文件后寻找1024字节,那为什么length - offset = 1024,如果你的文件小于1kb,那么第一次调用, 它已经寻求文件结束。这是您丢失数据的地方。

第二次调用它,它

不寻求,因为你没有向读取器发送任何读取请求,所以它认为不变,那么它就不需要再次读取文件来检查文件末尾是否,为什么第二次调用不会丢失数据。