簡體   English   中英

從流創建Zip文件並下載它

[英]Creating Zip file from stream and downloading it

我有一個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); 
}

這會將數據集直接寫入zipfile中的壓縮流中。 效率很高! 沒有雙緩沖。 在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...

編輯:再次看了這個,並且意識到使用了Codeplex的Ionic.Ziplib ,我稍微更改了代碼,而不是zipFile.Save(Response.OutputStream); 我用過zipFile.Save(stream); 使用MemoryStream類的stream實例並使用Response.Write(stream);將其寫出來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();

您正在使用Save方法將zipFile保存到響應流,但是您還使用zipstream變量調用Response.Write()。 什么是zipstream? 檢查它也不是空流。

此代碼將幫助您從流中下載文件。

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;

從流創建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());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM