从stream中创buildZip文件并下载
我有一个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文件是空的。
2件事。 首先,如果您保留了代码devise,则需要先在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); }
即使你保留这个devise,我也会build议一个using()子句,正如我所示,并且如所有DotNetZip示例中所述 ,代替调用Dispose()。 using()子句在失败时更可靠。
现在你可能会想,为什么在调用AddEntry()之前需要在MemoryStream中寻找? 原因是,AddEntry()被devise为支持那些通过位置是重要的stream的调用者。 在这种情况下,调用者需要使用stream的当前位置从stream中读取条目数据。 AddEntry()支持。 因此,在调用AddEntry()之前在stream中设置位置。
但是,更好的select是修改代码以使用接受WriteDelegate的AddEntry()的重载 。 它是专门为将数据集添加到zip文件而devise的。 您的原始代码将数据集写入内存stream,然后在stream上寻找,并将stream的内容写入压缩文件。 如果您只写一次数据,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); }
这将数据集直接写入压缩文件中的压缩stream。 非常高效! 没有双缓冲。 匿名委托在ZipFile.Save()时被调用。 只执行一次写入(+压缩)。
你为什么不closuresMemoryStream,我将它包装在一个using
子句中,对于zipFile
也可以zipFile
? 此外,我还假设是一个DataTable …放入错误检查,看看是否有行,请参阅下面的代码…
dt.TableName =“声明”; if(dt.Rows!= null && dt.Rows.Count> = 1){ 使用(MemoryStream stream = new MemoryStream()){ dt.WriteXml(stream); //感谢Cheeso / Mikael stream.Seek(0,SeekOrigin.Begin); // 使用(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); //评论这一点 / * 回复于(zipstream); // <-----这是从哪里来的? * / } 回复于(stream); } } //没有行...不要打扰...
编辑:再次看了这个,并意识到从Codeplex的Ionic.Ziplib被使用,我稍微改变了代码,而不是zipFile.Save(Response.OutputStream);
我用zipFile.Save(stream);
使用MemoryStream
类的stream
实例并使用Response.Write(stream);
将其写出Response.Write(stream);
。
编辑#2:感谢Cheeso + Mikael指出了这个明显的缺陷 – 我错过了一英里的路程,直到我意识到这个stream是在最后才知道他们的意见。
希望这有助于,最好的问候,汤姆。
你有没有尝试冲洗之前压缩stream?
dt.WriteXml(stream); stream.Flush(); ZipFile zipFile = new ZipFile();
好。 看起来好像我们在这里变得很远,所以你需要开始更多的debugging。
更新你的代码来执行以下操作:
dt.WriteXml(stream); stream.Seek(0, SeekOrigin.Begin); File.WriteAllBytes("c:\test.xml", stream.GetBuffer());
看看你是否有一个有效的XML文件。 如果你这样做,那么继续前进你的ZipFile。 将其保存到本地文件。 看看它是否存在,有你的XML文件,你的XML文件中有内容。
如果是这样的话,试着回应一下内存stream作为回应,看看是否有效。
那么你应该能够进一步追踪问题。
添加一个ContentType标头:
Response.ContentType = "application/zip";
这将允许浏览器检测您发送的内容。
仔细检查你正在返回的stream。 在你的例子下面
zipFile.Save(Response.OutputStream); Response.Write(zipstream); zipFile.Dispose();
您正在使用Save方法将zipFile保存到您的响应stream中,但是您也使用zipstreamvariables调用Response.Write()。 什么是zipstream? 检查它是不是一个空的stream。
此代码将帮助您从stream中下载文件。
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;
从stream中创build一个zip文件并下载。 下面是代码。
FileStream stream=File.OpenRead(@"D:\FileDownLoad\DeskTop\1.txt"); MemoryStream MS=new MemoryStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(MS); zipOutputStream.SetLevel(9); ZipEntry entry = new ZipEntry("1.txt"); zipOutputStream.PutNextEntry(entry); byte[] buffer = new byte[stream.Length]; int byteRead = 0; while ((byteRead = stream.Read(buffer, 0, buffer.Length)) > 0) zipOutputStream.Write(buffer, 0, byteRead); zipOutputStream.IsStreamOwner = false; stream.Close(); zipOutputStream.Close(); MS.Position = 0; Response.ContentType = "application/application/octet-stream"; Response.AppendHeader("content-disposition", "attachment; filename=\"Download.zip\""); Response.BinaryWrite(MS.ToArray());
- 驻留在App_Code中的类不可访问
- 什么是IIS应用程序池?
- 将所有的第一个字母转换为大写,每个单词都要低一些
- MVC2中的Html.Partial(view,model)和Html.RenderPartial(view,model)之间有什么区别(如果有的话)?
- 什么是“_vti_cnf”,“_vti_pvt”,“_vti_script”和“_vti_txt”文件夹?
- appSettings vs applicationSettings。 appSettings过时了吗?
- 如何将水晶报表绑定到手动创build的数据集
- 调用wkhtmltopdf从HTML生成PDF
- 通过jQuery调用ASP.NET服务器端的方法