有两件事。首先,如果您保留当前的代码设计,则需要在将MemoryStream写入条目之前执行Seek()。
dt.TableName = "Declaration";
MemoryStream stream = new MemoryStream();
dt.WriteXml(stream);
stream.Seek(0,SeekOrigin.Begin);
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()从句来替代调用Dispose(),如我所示,并且在
DotNetZip examples中描述的。在面对失败时,using()从句更加可靠。
现在你可能会想,为什么在调用AddEntry()之前需要在MemoryStream中寻找?原因是,AddEntry()被设计为支持那些传递了流并且位置很重要的调用者。在这种情况下,调用者需要从流中读取条目数据,使用流的当前位置。AddEntry()支持此操作。因此,在调用AddEntry()之前设置流中的位置。
但是,更好的选择是修改您的代码以使用接受WriteDelegate的
overload of AddEntry()。它专门为将数据集添加到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()时被调用。仅执行一次写入(+压缩)。