有没有什么理由GZipStream.Read会返回少于请求的字节数?

时间:2012-02-17 04:46:51

标签: c# stream buffer

The docs say

  

返回值
  读入缓冲区的总字节数。如果当前没有多个字节可用,则这可能小于请求的字节数,如果已到达流的末尾,则可以小于零(0)。

但是为什么从磁盘读取时字节“不可用”?


让我澄清一下:

  1. 我正在从磁盘读取(基础类型为FileStream
  2. 至少 N字节需要阅读(EOF之前)
  3. 我请求阅读N字节
  4. 在这种情况下,返回值/读取的字节数是否会小于N

4 个答案:

答案 0 :(得分:2)

回答您编辑过的问题:

  

在这种情况下,返回值/读取的字节数是否会小于N?

我认为你需要问一位硬件专家,我认为这不是引起这样一个人注意的正确论坛。

免责声明:我不是硬件专家,我不会在电视上播放。这只是猜测:

认为当你从磁盘读取时,你得到的字节数比你请求的更少的唯一原因是因为流已经用完了你的字节数。但是,可以想象您可能遇到类似于网络流的情况,其中您的程序读取字节的速度比硬件提供的速度快。在这种情况下,Read方法可能只是部分填充缓冲区然后返回。

显然,问题的答案取决于是否会出现这种情况。我认为答案是“不”。我当然没见过反例。但是根据这个假设编写代码是错误的。

考虑一下:即使您可以检查您的代码将运行的所有硬件的规格,并证明缓冲区将始终完全填充,直到达到流的末尾,没有人说可能有什么新的磁盘驱动器将来安装在机器上,可能会有不同的表现。只是对所有流进行相同的处理要简单得多,并且需要进行适量的工作来处理缓冲区未完全填充的可能性。

答案 1 :(得分:1)

Stream.Read要求您预先分配要读入的空间,如果您分配更多空间然后可以从流中读取,那么返回值就是告诉您已经有多少空间的方式使用

请考虑以下事项:

如果您分配了一个4096字节的缓冲区并且在2046处达到了EOF,那么返回值将只是2046.这可以让您知道在返回时您的缓冲区已满了多少。

答案 2 :(得分:1)

压缩流是包装流 - 因此行为取决于底层流的行为。因此,它具有与通用流“可以返回少于请求的字节数”相同的限制。

至于潜在的原因(劳埃德提供see also

  • 上次阅读时达到了EOF
  • 网络流中没有数据
  • Custom stram决定以固定大小的块返回数据(完全可以)。

答案 3 :(得分:1)

我的解决方案:

public static class StreamExt
{
    public static void ReadBytes(this Stream stream, byte[] buffer, int offset, int count)
    {
        int totalBytesRead = 0;
        while (totalBytesRead < count)
        {
            int bytesRead = stream.Read(buffer, offset + totalBytesRead, count - totalBytesRead);
            if (bytesRead == 0) throw new IOException("Premature end of stream");
            totalBytesRead += bytesRead;
        } 
    }
}

使用此方法应该安全地读入您请求的所有字节。