从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());