質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

1938閲覧

【C#】Jsonファイルをzip化して保存したい

gontya

総合スコア3

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

1クリップ

投稿2022/05/15 03:02

前提・実現したいこと

Jsonファイルをzip化して保存したい

お世話になります。

現在、Jsonファイルの編集ツールを作成しており保存にあたって
json形式で保存するものとzip形式で保存するものの選択肢を与えてsaveする機能
を作成したいと考えております。

試したこと

FileDialog.Filter プロパティを用いてjsonおよびzip拡張子を選べるように実装いたしました。

json拡張子を選択した場合は特に問題なく保存でき、保存したファイルを再度デシリアライズして開くことができます。

問題はzipファイルの方でして、保存自体はすることができますが
保存したzipファイルを開こうとすると

フォルダーを開くことができません。
圧縮フォルダーは無効です

とエラーが起きてしまいます。

SaveFileDialogでzip化する方法をご教授いただけますと幸いです。

(別の方法でjson形式で保存するボタンとzip形式で保存するボタンも設置しようかとも考えましたがこちらの方がスマートなのかなと思っています。
ただzip化の後aesの暗号化もしたいと考えているので、別ボタンにする方が実装する上では都合がよいのかとも考えております..

上記の点も踏まえてご教授いただけますと幸甚です。

該当のソースコード

C#

1private void SaveAsButton_Click(object sender, RoutedEventArgs e) 2 { 3 var dialog = new SaveFileDialog(); 4 dialog.Filter = "json|*.json|zip|*.zip"; 5 if (dialog.ShowDialog() == true) 6 { 7 var json = JsonConvert.SerializeObject(_data, Formatting.Indented); 8 File.WriteAllText(dialog.FileName, json); 9 } 10 }

wpf

1<Button 2 Click="SaveAsButton_Click" 3 Content="保存" 4/>

定義

C#

1public MainWindow() 2 { 3 InitializeComponent(); 4 DataContext = _data; 5 } 6 7private void OpenButton_Click(object sender, RoutedEventArgs e) 8 { 9 var dialog = new OpenFileDialog { Filter = "json|*.json", }; 10 if (dialog.ShowDialog() == true) 11 { 12 var json = File.ReadAllText(dialog.FileName); 13 _data = JsonConvert.DeserializeObject<ObservableCollection<PersonalData>>(json); 14 DataContext = _data; 15 } 16 }
tranokado👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/05/16 23:27 編集

質問者さん、その後無言ですが、下の回答ののコメントに書いたように質問のコードにある dialog.FileName からあなたが必要な「ファイル名と保存場所」を取得できない、または方法が分からないならその旨レスしてください。
guest

回答1

0

ベストアンサー

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); } } } }

パス名、ファイル名の操作、文字列の操作という基本的なことの知識を習得する必要がありそうです。勉強してください。

投稿2022/05/15 03:16

編集2022/05/18 01:46
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gontya

2022/05/15 05:17

ご教授ありがとうございます。 参考に一度コーディングしてみますね! 少々お待ちいただければと思いますm
退会済みユーザー

退会済みユーザー

2022/05/15 06:22

分からなかったら質問してください。
gontya

2022/05/15 22:30

遅くなってしまい申し訳ございません。 頂いた参考ページにつきまして質問をさせてください。 1.メモリストリーム上にZipArchiveを作成する理由について 2.ZipArchive.CreateEntry メソッドについて CreateEntryの引数につきまして、 作成されるエントリの名前を指定する、アーカイブのルートを基準とするパス が必要であるようなのですが、今回の場合何にあたるのでしょうか。 パスといっても今回新しく作るファイルでは..?と考えていたら分からなくなってしまいましたm
退会済みユーザー

退会済みユーザー

2022/05/16 01:09

上の質問へのレスはコメント欄では書けないので回答欄に追記します。
gontya

2022/05/16 11:07 編集

ご丁寧にありがとうございます。 お伝え漏れしており大変申し訳ないのですが、今回下記の仕様を目標に実装しておりました。 1.保存名を可変に 2.保存するパス(場所)を可変に 調べていくとやはりパス指定して実装している記事が多く、 >分からなくなってしまいましたm という状態になってしまいました。 上記の目標はこのライブラリだと難しいですかね..
退会済みユーザー

退会済みユーザー

2022/05/16 11:37

> 1.保存名を可変に > 2.保存するパス(場所)を可変に あなたの言う「可変」とはどういうこと? 上のサンプルで言うと path と "test.json" を任意に設定したいということであれば、そんなことはコードを見れば明らかに可能なのは分かるはず。そうでないなら一体何がしたいのか?????
gontya

2022/05/16 11:49

すみません、言い方が悪かったです。 ここでいう可変というのはコード(C#内)を書き換えることによって、ファイルパスと名前が変更かと思います。 私が実装目標としておりますのは、保存ボタンを押した際に SaveFileDialogでエクスプローラーを開き、そのユーザーが各々ファイル名と保存場所を指定することができるものになります。 まとめるとコード内を触らず、実行中にファイル名とパスを指定できる機能ですね。
退会済みユーザー

退会済みユーザー

2022/05/16 12:00

> 私が実装目標としておりますのは、保存ボタンを押した際にSaveFileDialogでエクスプローラーを開き、そのユーザーが各々ファイル名と保存場所を指定することができるものになります。 あなたのコードにある dialog.FileName に保存するファイルのフルパスが格納されているのでは? そうであれば、それからあなたの言う「各々ファイル名と保存場所」が取得できて、それを設定することは容易にできますけど。そういうこととは違うのでしょうか? 一体何がしたくて何を言ってるのでしょうかという感じなんですけど・・・
退会済みユーザー

退会済みユーザー

2022/05/16 22:58

質問者さん、その後無言ですが、上に書いたように質問のコードにある dialog.FileName からあなたが必要な「ファイル名と保存場所」を取得できない、または方法が分からないならその旨レスしてください。
gontya

2022/05/17 23:34 編集

確かに、dialog.FileNameを用いてファイル名と保存場所を指定することができました。 ありがとうございます! 1点お伺いしたいのですが、 var entry = zipArchive.CreateEntry("test.json"); の"test.json"の部分はstringだと思うのですが、こちらもdialog.FileNameで指定した名称に変更することってできますでしょうか? 文字列でなければならないようなので少しやり方を変えなければならないのかなと思ってますが。
退会済みユーザー

退会済みユーザー

2022/05/18 00:57

> 1点お伺いしたいのですが、var entry = zipArchive.CreateEntry("test.json"); の"test.json"の部分はstringだと思うのですが、こちらもdialog.FileNameで指定した名称に変更することってできますでしょうか? もちろんできます。後で例を回答欄に書いておきます。
gontya

2022/05/18 13:02

追記のほどありがとうございました。 全体的な基礎的知識がないと組み合わせて感がることができないと実感しています。 勉強不足であったにもかかわらず、お付き合いいただきありがとうございました! 精進します
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問