ASP.NET Core 將文件夾內容輸出為壓縮包文件方法


本文主要是告訴大家一個省內存的方法,將整個文件夾的內容作為一個壓縮包輸出,但是實際上沒有申請那么多的內存,也不需要升級創建一個壓縮包文件。原理是通過逐個讀文件然后按照壓縮包格式輸出

本文主要是告訴大家一個省內存的方法,將整個文件夾的內容作為一個壓縮包輸出,但是實際上沒有申請那么多的內存,也不需要升級創建一個壓縮包文件。原理是通過逐個讀文件然后按照壓縮包格式輸出

在每個請求的方法可以拿到 HttpContext 屬性,通過這個屬性拿到 Response 屬性,在這里可以使用 BodyWriter 屬性,在這個屬性里面寫入的內容將會被客戶端下載

而這個屬性可以作為 Stream 請看下面代碼

using var stream = HttpContext.Response.BodyWriter.AsStream();
C#

在 .NET 中可以通過 ZipArchive 將一個文件夾的文件按照壓縮文件格式寫入,還可以設置壓縮的壓縮率等,可以設置文件所在文件夾的路徑

通過在這個 stream 創建一個 ZipArchive 類,然后在這個類里面創建文件的方法就可以做到不斷向客戶端發送文件,發送的文件都在一個壓縮包里面

/// <summary> /// 將一個文件夾的內容讀取為 Stream 的壓縮包 /// </summary> /// <param name="directory"></param> /// <param name="stream"></param> 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();     } }
C#

上面的代碼可以讓運行的程序不需要申請和需要傳輸一樣大的內存空間,或者不需要先執行壓縮放在本地文件,可以不斷讀取本地文件然后上傳。讀取本地文件等都通過 CopyToAsync 自動設置緩存大小。如果不放心 CopyToAsync 方法設置的緩存大小,可以通過重載的方法手動設置緩存的大小

await toZipStream.CopyToAsync(stream, bufferSize: 100);
C#

上面的代碼設置了文件不要壓縮,因為作為文件傳輸的時候,實際上我的業務是在內網傳輸,我的磁盤讀取速度大概是 20M 一秒,而網絡傳輸是 10M 一秒,也就是此時的壓縮其實沒什么意義,壓縮減少的內容減少的傳輸時間就和壓縮的時間差不多

如果小伙伴需要傳輸的時候壓縮,請設置 zipArchive.CreateEntry 方法

當然此方法的缺點是,也許傳輸的時候服務器自己讀取文件炸了,此時就會傳輸的文件不對,同時客戶端不知道服務器傳的對不對,因為壓縮的大小沒有告訴客戶端。如果要告訴客戶端壓縮后的大小就需要先在服務器端進行壓縮。本文的方法設置的是沒有壓縮率的壓縮,大概的大小還可以告訴用戶

此方法可以如何使用?在隨意一個 Get 方法里面就可以通過 HttpContext 傳入 Response 屬性

在使用 BodyWriter 寫入之前需要先設置 StatusCode 的值

HttpContext.Response.StatusCode = StatusCodes.Status200OK;  using var stream = HttpContext.Response.BodyWriter.AsStream();
C#

假設需要返回的文件夾是 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); }
C#

本地我寫了一個 PowerShell 腳本運行

For ($i=0; $i -le 100000; $i++) {  (new-object System.Net.WebClient).DownloadFile("http://localhost:5000/File/doubi", "F:\lindexi\zip\2.zip") }
C#

本地運行這個腳本可以看到內存其實沒有 GC 也沒有溢出,我運行看到內存大概在 100M 左右

獲取的時候會占用一些 CPU 資源,但是很省內存


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM