2016-11-29 7 views
0

私のウェブサイトでは、ユーザーが特定のボタンをクリックすると、たくさんのファイルをzip形式でアーカイブして送信する必要があります。ファイル自体は第3の部分によって生成され、私はURLだけを持っています。 私はそれに部分的に成功しましたが、いくつか問題があります。作成中のzipファイルを送信する

まず、zipファイルがたくさんある場合、zipファイルを最初に作成して送信するため、サーバーの応答が遅くなります。しばらくするとクラッシュすることがあります(特に、「オーバーフローまたはアンダーフローが算術演算に発生します。」)。

次に、zipアーカイブが完了したらすぐにファイルが送信されます。代わりにすぐにダウンロードを開始したいと思います。すなわち、ユーザがダイアログから「保存」をクリックするとすぐに、データが送信を開始し、zipファイルが「オンザフライ」で作成されている間、送信が続けられます。私はいくつかのウェブサイトでその機能を見てきました。例えば、http://download.muuto.com/

問題は、どうやってそれを行うのか分かりません。

私はこの質問からコードの一部を使用している:Creating a dynamic zip of a bunch of URLs on the fly そして、このブログの記事から:http://dejanstojanovic.net/aspnet/2015/march/generate-zip-file-on-the-fly-in-aspnet-mvc-application/

にzipファイル自体をASP.NET MVCコントローラの方法で作成して返します。ここに私のコードは次のとおりです。

using ICSharpCode.SharpZipLib.Zip; 
using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Web; 
using System.Web.Mvc; 

namespace MyProject.Controllers 
{ 
    public class MyController : Controller 
    {   
     public ActionResult DownloadFiles() 
     { 
      var files = SomeFunction(); 

      byte[] buffer = new byte[4096]; 

      var baseOutputStream = new MemoryStream(); 
      ZipOutputStream zipOutputStream = new ZipOutputStream(baseOutputStream); 
      zipOutputStream.SetLevel(0); //0-9, 9 being the highest level of compression 
      zipOutputStream.UseZip64 = UseZip64.Off; 
      zipOutputStream.IsStreamOwner = false; 

      foreach (var file in files) 
      { 
       using (WebClient wc = new WebClient()) 
       { 
        // We open the download stream of the file 
        using (Stream wcStream = wc.OpenRead(file.Url)) 
        { 
         ZipEntry entry = new ZipEntry(ZipEntry.CleanName(file.FileName)); 
         zipOutputStream.PutNextEntry(entry); 

         // As we read the stream, we add its content to the new zip entry 
         int count = wcStream.Read(buffer, 0, buffer.Length); 
         while (count > 0) 
         { 
          zipOutputStream.Write(buffer, 0, count); 
          count = wcStream.Read(buffer, 0, buffer.Length); 
          if (!Response.IsClientConnected) 
          { 
           break; 
          } 
         } 
        } 
       } 
      } 
      zipOutputStream.Finish(); 
      zipOutputStream.Close(); 

      // Set position to 0 so that cient start reading of the stream from the begining 
      baseOutputStream.Position = 0; 

      // Set custom headers to force browser to download the file instad of trying to open it 
      return new FileStreamResult(baseOutputStream, "application/x-zip-compressed") 
      { 
       FileDownloadName = "Archive.zip" 
      }; 
     } 
    } 
} 
[OK]を
+0

が重複する可能性が。 net with SharpZipLib](http://stackoverflow.com/questions/626196/streaming-a-zip-file-over-http-in-net-with-sharpziplib) –

+0

明確に関連している(同じ目標)が、重複していない:IそれはMVCコントローラからやろうとしていますが、これは別のアプローチです。私は 'BufferOutput = false'を別の方法で使用しようとしましたが、あまり変更されていないようです。 – Ogier

+0

違いはありません。ストリームをパラメータとして受け取る 'FileResult'を返すことができます –

答えて

1

応答のOutputStreamとバッファリングでビットをいじることで、私は解決策に到着しました:[にHTTP経由でzipファイルをストリーミングの

using ICSharpCode.SharpZipLib.Zip; 
using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Web; 
using System.Web.Mvc; 

namespace MyProject.Controllers 
{ 
    public class MyController : Controller 
    {   
     public ActionResult DownloadFiles() 
     { 
      var files = SomeFunction(); 

      // Disable Buffer Output to start the download immediately 
      Response.BufferOutput = false; 

      // Set custom headers to force browser to download the file instad of trying to open it 
      Response.ContentType = "application/x-zip-compressed"; 
      Response.AppendHeader("content-disposition", "attachment; filename=Archive.zip"); 

      byte[] buffer = new byte[4096]; 

      ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream); 
      zipOutputStream.SetLevel(0); // No compression 
      zipOutputStream.UseZip64 = UseZip64.Off; 
      zipOutputStream.IsStreamOwner = false; 

      try 
      { 
       foreach (var file in files) 
       { 
        using (WebClient wc = new WebClient()) 
        { 
         // We open the download stream of the image 
         using (Stream wcStream = wc.OpenRead(file.Url)) 
         { 
          ZipEntry entry = new ZipEntry(ZipEntry.CleanName(file.FileName)); 
          zipOutputStream.PutNextEntry(entry); 

          // As we read the stream, we add its content to the new zip entry 
          int count = wcStream.Read(buffer, 0, buffer.Length); 
          while (count > 0) 
          { 
           zipOutputStream.Write(buffer, 0, count); 
           count = wcStream.Read(buffer, 0, buffer.Length); 
           if (!Response.IsClientConnected) 
           { 
            break; 
           } 
          } 
         } 
        } 
       } 
      } 
      finally 
      { 
       zipOutputStream.Finish(); 
       zipOutputStream.Close(); 
      } 

      return new HttpStatusCodeResult(HttpStatusCode.OK); 
     } 
    } 
} 
関連する問題