當前位置: 華文頭條 > 推薦

在 WebAPI 裏生成 csv zip 檔

2024-02-07推薦

在 WebAPI 裏生成 csv zip 檔

Intro

前段時間在寫一個匯出 csv 壓縮包的 API,踩了一些坑,記錄一下同分時享一下避免大家踩坑

Sample

API 是匯出一個 zip 壓縮包,這個壓縮包裏一些 csv 檔

csv 用的是 CsvHelper 來匯出的,zip 是用的 .NET 裏內建的 ZipArchive 來實作的,完整的匯出程式碼如下:

[HttpPost("download" ) ]
public async Task<IActionResult> DownloadCsv ( )
{
var books = Get();

var memoryStream = new MemoryStream();
using (var zip = new ZipArchive(memoryStream, ZipArchiveMode.Create, true ))
{
foreach (var group in books
.GroupBy(t => new
{
t.Author
}))
{
var entryName = $"{group .Key.Author} .csv" ;
var entry = zip.CreateEntry(entryName);

await using var writer = new StreamWriter(entry.Open());
await using var csv = new CsvWriter(writer, new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false
});

// register class map if necessary
// csv.Context.Register classMap< classMap>();

await csv.WriteRecordsAsync(group );
}
}
memoryStream.Seek(0 , SeekOrigin.Begin);
return File(memoryStream, "application/zip" , "books.zip" );
}

說一說可能會踩到坑:

  • memory stream 首先不能 using,因為要寫入到 response 裏

  • ZipArchive create 的時候需要指定 ZipArchiveMode.Create 並且, leaveOpen 需要指定為 true ,原因同上,預設會 dispose stream

  • CsvHelper 要寫入 entry 的時候可以直接用 ZipArchiveEntry Open() 方法來獲取對應的 stream,直接寫入 entry 的 stream

  • ZipArchive 不要使用 using var zip = new ZipEntry(..); 這樣的寫法,這樣寫會有問題,會導致 ZipArchive 不會及時 dispose 導致 stream 數據是有問題的,使用 using {} 的形式,自己控制 using 的 scope

  • 最後匯出之前需要把 memory stream 重設到開始的位置,可以使用 memoryStream.Seek(0, SeekOrigin.Begin) ,否則也會導致匯出異常

  • 匯出效果:

    References

  • https://github.com/WeihanLi/SamplesInPractice/blob/main/AspNetCoreSample/Controllers/BooksController.cs#L39

  • https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs

  • https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs