GZipStream.Read返回的字节数少于请求的字节数有什么原因吗

本文关键字:字节数 什么 请求 返回 Read 于请求 GZipStream | 更新日期: 2023-09-27 18:24:59

文档说:

返回值:
读取到缓冲区的总字节数。如果当前没有那么多字节可用,则这可以小于请求的字节数,或者如果已经到达流的末尾,则可以为零(0)。

但是,为什么从磁盘读取时字节"不可用"呢?


让我澄清一下:

  1. 我正在从磁盘读取(底层类型为FileStream
  2. 至少还有N字节需要读取(在EOF之前)
  3. 我请求读取N字节

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

GZipStream.Read返回的字节数少于请求的字节数有什么原因吗

回答您编辑的问题:

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

我想你需要问一位硬件专家,我想这不是吸引这样一个人注意的合适论坛。

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

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

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

考虑一下:即使你可以模拟代码运行的所有硬件的规格,并证明缓冲区总是会被完全填满,直到流结束,也不知道将来有人可能在机器上安装什么新的磁盘驱动器,这可能会有不同的表现。只需对所有流进行相同的处理,并承担处理缓冲区未完全填充的可能性所需的少量工作,就简单得多。

我的解决方案:

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;
        } 
    }
}

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

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

至于潜在原因(另见Lloyd提供的)

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

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

考虑以下内容:

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