我有一个 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件事。首先,如果保留现有的代码设计,则需要在将 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 示例, ,代替调用 Dispose()。using() 子句在出现故障时更加可靠。

现在你可能想知道,为什么在调用AddEntry()之前需要在MemoryStream中查找呢?原因是,AddEntry() 旨在支持那些传递位置很重要的流的调用者。在这种情况下,调用者需要从流中读取条目数据, 使用流的当前位置. 。AddEntry() 支持这一点。因此,请在调用 AddEntry() 之前设置流中的位置。

但是,更好的选择是修改您的代码以使用 接受 WriteDelegate 的 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); 
}

这会将数据集直接写入 zip 文件中的压缩流中。非常高效!没有双缓冲。匿名委托在 ZipFile.Save() 时被调用。仅执行一次写入(+压缩)。

其他提示

你为什么不关闭的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...

编辑:有这个又看了看,并认识到 Ionic.Ziplib 从使用Codeplex上,我稍微改变的代码,而不是zipFile.Save(Response.OutputStream);我使用zipFile.Save(stream);类的stream实例,并使用MemoryStream写出来使用Response.Write(stream);

修改#2:感谢的 Cheeso + <强> 的Mikael 作为指出明显的缺陷 - 我错过了一英里关闭,直到我意识到流是在结束...

没明白自己的评论

你尝试过压缩和解之前刷新流?

dt.WriteXml(stream);
stream.Flush();
ZipFile zipFile = new ZipFile();

确定。它似乎并不像我们得到了很远,你在这儿需要开始调试这个多一点。

更新你的代码执行以下操作:

dt.WriteXml(stream);
stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes("c:\test.xml", stream.GetBuffer());

看看你是否有一个有效的XML文件了。如果再往前上做同样的你的ZipFile。它保存到本地文件。看看它的存在,你的XML文件和XML文件有内容了。

如果这样的作品,尝试发送回只是存储器流作为响应,看看是否能工作的。

您应该然后能够进一步追踪问题了。

添加ContentType标头:

Response.ContentType = "application/zip";

这将允许浏览器检测到您所发送的内容。

仔细检查你正在返回回过流。另外,在以下

的示例
zipFile.Save(Response.OutputStream);
Response.Write(zipstream);
zipFile.Dispose();

您正在保存的zip文件使用Save方法的响应流,但你还呼吁的Response.Write()与zipstream变量。什么是zipstream?检查它是不是一个空流过。

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

这个代码将有助于你从下载流的文件。

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;
scroll top