我有一个DataTable,我想将它转换为xml然后使用DotNetZip压缩它。最后用户可以通过Asp.Net网页下载。 我的代码在下面
dt.TableName = "Declaration";
MemoryStream stream = new MemoryStream();
dt.WriteXml(stream);
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);
//Response.Write(zipstream);
zipFile.Dispose();
zip文件中的xml文件为空。
答案 0 :(得分:69)
2件事。首先,如果你保留了你的代码设计,你需要先在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()旨在支持那些传递位置很重要的流的调用者。在这种情况下,调用者需要使用流的当前位置从流中读取条目数据。 AddEntry()支持它。因此,在调用AddEntry()之前在流中设置位置。
但是,更好的选择是修改代码以使用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()时调用匿名委托。仅执行一次写入(+压缩)。
答案 1 :(得分:6)
为什么不关闭MemoryStream,我会将其包含在using
子句中,zipFile
也可以这样说?另外dt
我假设是一个DataTable ...进行错误检查以查看是否有行,请参阅下面的代码......
dt.TableName = "Declaration"; if (dt.Rows != null && dt.Rows.Count >= 1){ using (MemoryStream stream = new MemoryStream()){ dt.WriteXml(stream); // Thanks Cheeso/Mikael 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); zipFile.Save(stream); // Commented this out /* Response.Write(zipstream); // <----- Where did that come from? */ } Response.Write(stream); } } // No rows...don't bother...
修改:再次查看此内容,并意识到使用了Codeplex中的Ionic.Ziplib,我稍微更改了代码,而不是zipFile.Save(Response.OutputStream);
我使用zipFile.Save(stream);
使用stream
类的MemoryStream
实例并使用Response.Write(stream);
将其写出来。
编辑#2:感谢 Cheeso + Mikael 指出明显的缺陷 - 我错过了一英里的距离,直到我意识到这条小溪已经结束时才理解他们的评论......
答案 2 :(得分:1)
您是否尝试在压缩前刷新流?
dt.WriteXml(stream);
stream.Flush();
ZipFile zipFile = new ZipFile();
答案 3 :(得分:1)
确定。看起来好像我们在这里走得很远所以你需要开始调试这个。
更新您的代码以执行以下操作:
dt.WriteXml(stream);
stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes("c:\test.xml", stream.GetBuffer());
查看您是否有有效的XML文件。如果你这样做,那么继续使用你的ZipFile。将其保存到本地文件。看看它是否存在,您的xml文件和xml文件中是否包含内容。
如果可行,请尝试仅回送内存流作为响应,看看是否有效。
然后,您应该能够进一步跟踪问题。
答案 4 :(得分:0)
添加ContentType标题:
Response.ContentType = "application/zip";
这将允许浏览器检测您要发送的内容。
答案 5 :(得分:0)
仔细检查您要返回的流。在下面的示例中
zipFile.Save(Response.OutputStream);
Response.Write(zipstream);
zipFile.Dispose();
您正在使用Save方法将zipFile保存到响应流,但是您还使用zipstream变量调用Response.Write()。什么是zipstream?检查它也不是空流。
答案 6 :(得分:0)
此代码将帮助您从流中下载文件。
using (var outStream = new MemoryStream())
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
var fileInArchive = archive.CreateEntry("FileName.pdf", CompressionLevel.Optimal);
using (var entryStream = fileInArchive.Open())
using (WebResponse response = req.GetResponse())
{
using (var fileToCompressStream = response.GetResponseStream())
{
fileToCompressStream.CopyTo(entryStream);
}
}
}
using (var fileStream = new FileStream(@"D:\test.zip", FileMode.Create))
{
outStream.Seek(0, SeekOrigin.Begin);
outStream.CopyTo(fileStream);
}
}
需要命名空间:
using System.IO.Compression;
using System.IO.Compression.ZipArchive;
答案 7 :(得分:0)
从流创建zip文件并下载它。下面是代码。
id