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

C#.NET为什么解压流时需要Stream.Seek,c#,.net,zip,unzip,dotnetzip,C#,.net,Zip,Unzip,Dotnetzip,我正在从事一个项目,在这个项目中,我需要解压流和字节数组以及解压它们的能力。我正在运行一些单元测试,这些测试从一个流创建Zip,然后解压,当我解压它们时,DonNetZip将它们视为Zip的唯一方法是运行streamToZip.Seek(o,SeekOrigin.Begin)和streamToZip.Flush()。如果不这样做,我会在ZipFile.read(stream)上得到错误“无法读取块,没有数据” 我想知道是否有人能解释这是为什么。我看过一些关于使用它来实际设置相对读取位置的文章,但

我正在从事一个项目,在这个项目中,我需要解压流和字节数组以及解压它们的能力。我正在运行一些单元测试,这些测试从一个流创建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;
    }
解压缩对象:

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

当您从
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
将从
流位置开始

所以

我会成功的


离题但肯定有用:

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;
        }
    }
}
public IEnumerable UnZipObject(流数据)
{
使用(var zip=ZipFile.Read(数据))
{
foreach(zip中的var项)
{
var newStream=newmemoryStream();
项目.摘录(新闻流);
newStream.Position=0;
收益-收益-新闻流;
}
}
}
仅在迭代时才会解压内存中的所有项(因为
解压对象()
中使用了
MemoryStream
),这是因为提取的项已生成。(返回
IEnumerable
)有关生成的详细信息:


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

在哪里,用什么
Stream
调用
UnZipObject
?而且,在调用
UnZipObject
之前,你对该
流做了什么?
ZippedItem=output;
做了什么?感谢你提供了真实世界的类比…正是我所需要的!谢谢你的建议,我已经听过几次了imes指出最好传递字节数组而不是流,但我不确定我是否理解你的答案中的原因?我可以举一个例子说明你的建议吗?数组可以由多个线程并发读取,流不能,因为多个线程将更改
位置
属性。此外,字节数组将是o的“副本”原始河流。
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;
        }
    }
}