生成した複数のCSVファイルを、コントローラーからビューに渡す方法がわからずに苦戦したので書き残しておきます。
結論としてはZIPファイルに格納してからViewに渡すやり方が一番楽でした。
なおZIPファイルに格納するファイルはCSVファイル以外でも問題ありません。
CSVファイルを作成・出力する方法については以下の記事で解説しているので参考にしてください。
環境
- Windows10
- Visual Studio Community 2019
- .NET Framework 4.8
準備
ZIPファイルを作成するにあたっては、ZipArchiveクラスを使用します。
.NET Framework4.5以降で使用できるクラスですが、事前に参照の追加が必要です。
プロジェクト内の「参照」を右クリック→「参照の追加」をクリックします。
「System.IO.Compression」にチェックを入れてOKをクリックすれば準備完了です。
コードと解説
コントローラーでZIPファイルを生成してビューに渡すコードです。
※ModelやCSVファイル作成処理については、上記のCSVファイル出力方法の記事で解説しているため省略します。
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.IO;
using System.Text;
using System.Web.Mvc;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult ZipDownload(string download)
{
// ダウンロードボタンが押された際の処理
if (download == "download")
{
// リストを準備
var userList = new List<UserModel>
{
new UserModel { Id = 1, Name = "Mike", Age = 18 },
new UserModel { Id = 2, Name = "Jane", Age = 25 },
new UserModel { Id = 3, Name = "Bob", Age = 20 }
};
// csvファイルを2つ作成
var csv1 = CsvWriter.CreateCsv(userList);
var csv2 = CsvWriter.CreateCsv(userList);
// 空のメモリストリームを生成
using (var ms = new MemoryStream())
{
var date = DateTime.Now.ToString("yyyyMMdd");
// メモリストリームを指定してZipArchiveを作成
using (var archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
// ファイルネームの指定
var FileName1 = string.Format($"{date}_ユーザーリスト1.csv");
var FileName2 = string.Format($"{date}_ユーザーリスト2.csv");
// csvの文字列をbyte型配列に変換
byte[] FileBytes1 = Encoding.GetEncoding("Shift_JIS").GetBytes(csv1);
byte[] FileBytes2 = Encoding.GetEncoding("Shift_JIS").GetBytes(csv2);
// 1つ目のcsvをzipストリームに書き込む
var zipEntry = archive.CreateEntry(FileName1, CompressionLevel.Fastest);
using (var zipStream = zipEntry.Open())
{
zipStream.Write(FileBytes1, 0, FileBytes1.Length);
}
// 2つ目のcsvをzipストリームに書き込む
var zipEntry2 = archive.CreateEntry(FileName2, CompressionLevel.Fastest);
using (var zipStream = zipEntry2.Open())
{
zipStream.Write(FileBytes2, 0, FileBytes2.Length);
}
}
// メモリストリームを配列に変換してViewに渡す
return File(ms.ToArray(), "application/zip", date + "_ユーザーリスト.zip");
}
}
return View();
}
}
}
それでは、ZIPファイル作成の処理を詳しく見てみましょう。
// 空のメモリストリームを生成
using (var ms = new MemoryStream())
{
var date = DateTime.Now.ToString("yyyyMMdd");
// メモリストリームを指定してZipArchiveを作成
using (var archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
まずデータを書き込むための空のメモリストリームを生成し、そのストリームを指定してZipArchiveを作成します。
ZipArchiveModeをCreateとすることでアーカイブを作成できます。
第3引数のleaveOpenをtrueにすることで、ZipArchiveを破棄した後もストリームを開き続けることができます。
// 1つ目のcsvをzipストリームに書き込む
var zipEntry = archive.CreateEntry(FileName1, CompressionLevel.Fastest);
次にZipArchiveクラスのCreateEntryメソッドで、1つ目のZipArchiveEntryを作成します。
EntryとはZIPアーカイブ内にあるZIPファイルそのものを表すようです。
第2引数のCompressionLevelをFastestにすると、圧縮速度優先で圧縮を行います。
using (var zipStream = zipEntry.Open())
{
zipStream.Write(FileBytes1, 0, FileBytes1.Length);
}
ZipArchiveEntryのOpenメソッドを実行することでEntryのストリームを取得できます。
取得したストリームに1つ目のCSVの内容を書き込みます。
ちなみにStreamクラスのWriteメソッドは、第1引数に書き込むバイト配列、第2引数に開始位置、第3引数に書き込むバイト数を指定します。
// メモリストリームを配列に変換してViewに渡す
return File(ms.ToArray(), "application/zip", date + "_ユーザーリスト.zip");
格納するファイル数だけストリームへ書き込んだら、ストリームを配列に変換してビューに渡します。
<h2>ZIPファイルダウンロードページ</h2>
@using (Html.BeginForm("ZipDownload", "Home", FormMethod.Get))
{
<button class="btn btn-primary" value="download" name="download" type="submit">ファイルダウンロード</button>
}
参考までにビューも載せておきます。ボタンをクリックするとZIPファイルがダウンロードできます。
実行結果
ファイルダウンロードボタンを押すとZIPファイルがダウンロードされます。
ZIPファイルを開くと、無事に2つのCSVファイルが格納されていることが確認できました。
参考サイト
ZipArchiveクラスの使い方はこちらを参考にしました。
MemoryStreamクラスについてはこちらを参考にしました。
ASP.NET MVCにおけるZIPファイルのダウンロード方法についてはこちらが参考になりました。(海外サイト)