C# .NET 为什么在解压缩流时需要 Stream.Seek



我正在做一个项目,我需要能够解压缩流和字节数组以及压缩它们。我正在运行一些单元测试,这些测试从流中创建 Zip,然后解压缩它们,当我解压缩它们时,DonNetZip 将它们视为 zip 的唯一方法是运行 streamToZip.Seek(o,SeekOrigin.Begin)streamToZip.Flush()。如果我不这样做,我会在ZipFile.Read(stream)上收到错误"无法读取块,没有数据"。

我想知道是否有人可以解释为什么会这样。我已经看过一些关于使用它来实际设置相对读取位置的文章,但没有一篇真正解释为什么在这种情况下需要它。

这是我的代码:

压缩对象:

   public Stream ZipObject(Stream data)
    {
        var output = new MemoryStream();
        using (var zip = new ZipFile())
        {
            zip.AddEntry(Name, data);
            zip.Save(output);
            FlushStream(output);
            ZippedItem = output;
        }
        return output;
    }

解压缩对象:

 public List<Stream> UnZipObject(Stream data)
    {
        ***FlushStream(data); // This is what I had to add in to make it work***
        using (var zip = ZipFile.Read(data))
        {
            foreach (var item in zip)
            {
                var newStream = new MemoryStream();
                item.Extract(newStream);
                UnZippedItems.Add(newStream);
            }
        }
        return UnZippedItems;
    }

我必须添加的冲洗方法:

    private static void FlushStream(Stream stream)
    {
        stream.Seek(0, SeekOrigin.Begin);
        stream.Flush();
    }

当您从 ZipObject 返回 output 时,该流位于末尾 - 您刚刚写入了数据。您需要"倒带"它,以便可以读取数据。想象一下,你有一个录像带,刚刚录制了一个节目 - 你需要在观看之前倒带它,对吧?这里完全一样。

不过,我建议在ZipObject本身这样做 - 我不认为Flush电话是必要的。我个人也会使用 Position 属性:

public Stream ZipObject(Stream data)
{
    var output = new MemoryStream();
    using (var zip = new ZipFile())
    {
        zip.AddEntry(Name, data);
        zip.Save(output);
    }
    output.Position = 0;
    return output;
}

写入流时,位置会更改。如果要解压缩它(同一流对象),则需要重置位置。否则你会得到一个EndOfStreamException,因为ZipFile.Read将从stream.Position开始。

所以

stream.Seek(0, SeekOrigin.Begin); 

stream.Position = 0; 

会做这个伎俩。


题外话,但肯定有用:

public IEnumerable<Stream> UnZipObject(Stream data)
{
    using (var zip = ZipFile.Read(data))
    {
        foreach (var item in zip)
        {
            var newStream = new MemoryStream();
            item.Extract(newStream);
            newStream.Position = 0;
            yield return newStream;
        }
    }
}

不会解压缩内存中的所有项目(因为UnZipObject()中使用的MemoryStream,仅在迭代时解压缩。那是因为提取的物品是有收益的。(返回IEnumerable<Stream>)有关产量的更多信息:http://msdn.microsoft.com/en-us/library/vstudio/9k7k7cf0.aspx

通常我不会将返回的数据作为流重新注释,因为流类似于迭代器(使用 .位置作为当前位置)。这样,默认情况下它不是线程安全的。我宁愿将这些内存流作为ToArray()返回。

最新更新