C#.NET为什么解压流时需要Stream.Seek
我正在从事一个项目,在这个项目中,我需要解压流和字节数组以及解压它们的能力。我正在运行一些单元测试,这些测试从一个流创建Zip,然后解压,当我解压它们时,DonNetZip将它们视为Zip的唯一方法是运行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)上得到错误“无法读取块,没有数据” 我想知道是否有人能解释这是为什么。我看过一些关于使用它来实际设置相对读取位置的文章,但
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;
}
}
}