[ASP.netチュートリアル]ASP.NET Coreフォルダ内容を圧縮パッケージファイルに出力する方法

3386 ワード

本文は主にメモリを節約する方法を教えて、フォルダ全体の内容を圧縮パッケージとして出力しますが、実際にはそんなに多くのメモリを申請していません.圧縮パッケージファイルをアップグレードして作成する必要もありません.ファイルを1つずつ読んで圧縮パッケージ形式で出力するのが原理です
本文は主にメモリを節約する方法を教えて、フォルダ全体の内容を圧縮パッケージとして出力しますが、実際にはそんなに多くのメモリを申請していません.圧縮パッケージファイルをアップグレードして作成する必要もありません.ファイルを1つずつ読んで圧縮パッケージ形式で出力するのが原理です
リクエストごとにHttpContext属性を取得でき、この属性でResponse属性を取得できます.ここではBodyWriter属性を使用できます.この属性に書き込まれたコンテンツはクライアントにダウンロードされます.
この属性はStreamとして使用できます.次のコードを見てください.
  using var stream = HttpContext.Response.BodyWriter.AsStream();

はい.NETでは、ZipArchiveで1つのフォルダのファイルを圧縮ファイル形式で書き込むこともできますし、圧縮の圧縮率を設定することもできますし、ファイルがあるフォルダのパスを設定することもできます
このstreamでZipArchiveクラスを作成し、このクラスでファイルを作成する方法で、クライアントにファイルを送信し続けることができます.送信されたファイルは圧縮パッケージの中にあります.
  ///   ///              Stream       ///   ///   ///   public static async Task ReadDirectoryToZipStreamAsync(DirectoryInfo directory, Stream stream)  {   var fileList = directory.GetFiles();   using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create);   foreach (var file in fileList)   {    var relativePath = file.FullName.Replace(directory.FullName, "");    if (relativePath.StartsWith("\\") || relativePath.StartsWith("//"))    {     relativePath = relativePath.Substring(1);    }    var zipArchiveEntry = zipArchive.CreateEntry(relativePath, CompressionLevel.NoCompression);    using (var entryStream = zipArchiveEntry.Open())    {     using var toZipStream = file.OpenRead();     await toZipStream.CopyToAsync(stream);    }    await stream.FlushAsync();   }  }

上記のコードは、実行中のプログラムが申請や転送が必要なほどのメモリ領域を必要としないか、圧縮を実行してローカルファイルに置く必要がなく、ローカルファイルを読み取り続けてアップロードすることができます.ローカルファイルの読み込みなどは、CopyToAsyncで自動的にキャッシュサイズを設定します.CopyToAsyncメソッドで設定したキャッシュサイズが不安な場合は、リロードメソッドで手動でキャッシュサイズを設定できます.
  await toZipStream.CopyToAsync(stream, bufferSize: 100);

上のコードはファイルを圧縮しないように設定しています.ファイルとして転送するとき、実際に私の業務はイントラネットで転送されています.私のディスクの読み取り速度は20 M 1秒ぐらいですが、ネットワーク転送は10 M 1秒です.つまり、このときの圧縮は意味がありません.圧縮減少したコンテンツの減少した転送時間は圧縮の時間とあまり差がありません.
パートナーが転送するときに圧縮する必要がある場合はzipArchiveを設定します.CreateEntryメソッド
もちろん、この方法の欠点は、転送時にサーバが自分でファイルを読み取って爆発した場合、転送されたファイルが間違っていると同時に、クライアントはサーバの転送が正しいかどうか分からない.圧縮の大きさがクライアントに教えていないからだ.クライアントに圧縮後のサイズを教えるには、サーバ側で圧縮する必要があります.本稿の方法では圧縮率のない圧縮を設定し,おおよその大きさをユーザに伝えることもできる.
このメソッドはどのように使用できますか?任意のGetメソッドでは、HttpContextを介してResponseプロパティに転送できます.
BodyWriter書き込みを使用する前にStatusCodeの値を設定する必要があります
   HttpContext.Response.StatusCode = StatusCodes.Status200OK;   using var stream = HttpContext.Response.BodyWriter.AsStream();

戻るフォルダがf:\lindexi\test\であると仮定すると、以下のコードでフォルダを圧縮パッケージに出力できます.
  [HttpGet]  [Route("{id}")]  public async Task Get([FromRoute] string id)  {   var folder = @"f:\lindexi\test\";   HttpContext.Response.StatusCode = StatusCodes.Status200OK;   using var stream = HttpContext.Response.BodyWriter.AsStream();   await ReadDirectoryToZipStreamAsync(new DirectoryInfo(folder), stream);  }

PowerShellスクリプトの実行をローカルで書きました
For ($i=0; $i -le 100000; $i++) { (new-object System.Net.WebClient).DownloadFile(" "F:\lindexi\zip\2.zip")} 

このスクリプトをローカルで実行すると、実際にはGCもオーバーフローもなく、メモリを100 M程度で実行することができます.
取得時にCPUリソースを消費しますが、メモリは節約できます.
もし仲間がもっと良い方法があれば教えてください.