两件事.首先,如果保留现有的代码设计,则需要在将MemoryStream写入条目之前对其执行Seek().
dt.TableName = "Declaration";
MemoryStream stream = new MemoryStream();
dt.WriteXml(stream);
stream.Seek(0,SeekOrigin.Begin); // <-- must do this after writing the stream!
using (ZipFile zipFile = new ZipFile())
{
zipFile.AddEntry("Report.xml", "", stream);
Response.ClearContent();
Response.ClearHeaders();
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");
zipFile.Save(Response.OutputStream);
}
即使您保留这种设计,我也建议使用using()子句,正如我所展示的,以及所有DotNetZip examples条中所描述的,来代替调用Dispose().using()子句在遇到故障时更可靠.
现在您可能会想,为什么在调用AddEntry()之前需要在MemoryStream中查找?原因是,AddEntry()旨在支持那些通过位置重要的流的调用方.在这种情况下,调用者需要从流using the current position of the stream中读取条目数据.AddEntry()支持这一点.因此,在调用AddEntry()之前设置流中的位置.
但是,更好的 Select 是修改代码以使用overload of AddEntry() that accepts a WriteDelegate.它是专门为将数据集添加到zip文件而设计的.原始代码将数据集写入内存流,然后在该流上搜索,并将流的内容写入zip.如果只写一次数据,就会更快更容易,WriteDelegate允许您这样做.代码如下所示:
dt.TableName = "Declaration";
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");
using(Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
zipFile.AddEntry("Report.xml", (name,stream) => dt.WriteXml(stream) );
zipFile.Save(Response.OutputStream);
}
这会将数据集直接写入zipfile中的压缩流.非常高效!没有双缓冲.匿名委托在ZipFile.Save()时调用.仅执行一次写入(+压缩).