SaveFileDialogでzip化する方法をご教授いただけますと幸いです。
File.WriteAllText(dialog.FileName, json); というコードは、変数 json に代入されている JSON 文字列を dialog.FileName という名前のテキストファイルとして作成するだけです。
dialog.FileName のファイル名の拡張子が zip だからと言って zip 形式に変換して保存してくれるわけではなく、中身はやはりテキストファイルのはずです。試しにメモ帳で開いて中身を見てください。
何らかのライブラリを使ってテキストファイルを zip 形式に変換してから、File.WriteAllBytes メソッドを使って保存する必要があります。
【追記】
上に書いた「何らかのライブラリを使ってテキストファイルを zip 形式に変換」というのは以下の記事が参考になると思います。検討してみてはいかがですか?
byte配列に読み込んだファイルの内容をMemoryStream上でzipファイルにする
https://kiyokura.hateblo.jp/entry/2015/03/25/233117
【追記2】
下のコメントの 2022/05/16 10:09 の私のコメントで「・・・回答欄に追記します」と書いた件です。
1.メモリストリーム上にZipArchiveを作成する理由について
MemoryStream を使ったのはサンプルとして応用が利くようにするためだろうと思います。
Web アプリからダウンロードするなどでファイルを作りたくない場合もよくありますから。(FileStream を使うと、一旦ファイルを作成してサーバーのどこかに保存し、それをダウンロードして、終わったらファイルを削除するなど無駄なことをしなければなりません)
質問者さんのケースでファイルを作るという目的であれば FileStream を使ってもよさそうです。
2.ZipArchive.CreateEntry メソッドについて。CreateEntryの引数につきまして、作成されるエントリの名前を指定する、アーカイブのルートを基準とするパスが必要であるようなのですが、今回の場合何にあたるのでしょうか。
紹介した記事のコードの file.Name のことであれば、質問者さんのケースでは「任意のファイル名.json」で良いと思います。
例えば上で言った「任意のファイル名.json」を test.json として、test.zip という名前の zip ファイルを作るとすると、以下のようにすれば、
// 作成する test.zip ファイルのパス
var path = @"C:\...\test.zip";
var json = JsonConvert.SerializeObject(_data, Formatting.Indented);
// JSON 文字列からエンコーディング UTF-8 でバイト列を作成
var bytes = Encoding.UTF8.GetBytes(json);
// 紹介した記事のコードを利用
using (var ms = new MemoryStream())
{
// メモリストリーム上にZipArchiveを作成する
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
var entry = zipArchive.CreateEntry("test.json");
using (var es = entry.Open())
{
// エントリにバイナリを書き込む
es.Write(bytes, 0, bytes.Length);
}
}
// MemoryStream からバイト列を取得してファイルを作成
byte[] zipBytes = ms.ToArray();
File.WriteAllBytes(path, zipBytes);
// Web アプリでダウンロードするならバイト列を出力ストリームに書き出す
}
以下のような zip ファイルが上のコードの path に生成されます。
【追記3】
下のコメント欄の 2022/05/18 09:57 の私のコメントで「後で例を回答欄に書いておきます。」と書いた件です。
1点お伺いしたいのですが、var entry = zipArchive.CreateEntry("test.json"); の"test.json"の部分はstringだと思うのですが、こちらもdialog.FileNameで指定した名称に変更することってできますでしょうか?
ユーザーが SaveFileDialog で zip 形式を選んでファイル名を入力とすると dialog.FileName から取得できるファイル名の拡張子は .zip になっているはずですが、エントリー名の拡張子は .json にしたいのですよね?
であれば、dialog.FileName から Path.GetFileName メソッドで「ファイル名.拡張子」の文字列を取得し、String.Replace メソッドで zip を json に置き換えた文字列を取得し、それをエントリー名に設定してやれば良いです。
以下にサンプルを載せておきます。
private void SaveAsButton_Click(object sender, RoutedEventArgs e)
{
var dialog = new SaveFileDialog();
dialog.Filter = "json|*.json|zip|*.zip";
if (dialog.ShowDialog() == true)
{
var extension = System.IO.Path.GetExtension(dialog.FileName).ToLower();
if (extension == ".json")
{
// 質問者さんの JSON で保存するコード
var json = JsonConvert.SerializeObject(_data, Formatting.Indented);
File.WriteAllText(dialog.FileName, json);
}
if (extension == ".zip")
{
var filename = System.IO.Path.GetFileName(dialog.FileName);
var entryName = filename.Replace("zip", "json");
var json = JsonConvert.SerializeObject(_data, Formatting.Indented);
// JSON 文字列からエンコーディング UTF-8 でバイト列を作成
var bytes = Encoding.UTF8.GetBytes(json);
// 紹介した記事のコードを利用
using (var ms = new MemoryStream())
{
// メモリストリーム上にZipArchiveを作成する
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
var entry = zipArchive.CreateEntry(entryName);
using (var es = entry.Open())
{
// エントリにバイナリを書き込む
es.Write(bytes, 0, bytes.Length);
}
}
// MemoryStream からバイト列を取得してファイルを作成
byte[] zipBytes = ms.ToArray();
File.WriteAllBytes(dialog.FileName, zipBytes);
}
}
}
}
パス名、ファイル名の操作、文字列の操作という基本的なことの知識を習得する必要がありそうです。勉強してください。