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

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

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

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

Q&A

解決済

2回答

965閲覧

【C#】dialog.FileNameで取得した文字列で作成ファイル名を決定したい

gontya

総合スコア3

C#

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

1グッド

2クリップ

投稿2022/06/22 02:43

編集2022/06/22 03:35

前提・実現したいこと

お世話になります。
aes暗号化した際に出力されるファイル名をdialog.FileNameで取得した文字列で決定したいと考えています。

aes暗号化はできているため、作成ファイルの文字列を自由に設定できるようにする部分をご教授いただけますと幸いです。

試したこと

aes暗号化した際の出力ファイル設定を下記のように試しております。

  1. 出力パスを"C:/Users/Documents/test.aes"に設定

問題なくtestのaesファイルが作成される(ファイル名が可変ではないため要修正)

2 . 出力パスを System.IO.Path.GetFileNameで入力された文字列を読み取り、var aesName = filename.Replace("zip", "aes");で拡張子をaesに変更
暗号化ファイルが作成されない

文字列自体は1と同じだと思うので、ファイルが作成されない理由が分かりません。

該当コード

C#

1//AES暗号化 2 private void AesSaveAsButton_Click(object sender, RoutedEventArgs e) 3 { 4 var dialog = new SaveFileDialog(); 5 dialog.Filter = "zip|*.zip"; 6 if (dialog.ShowDialog() == true) 7 { 8 var filename = System.IO.Path.GetFileName(dialog.FileName); 9 10 var entryName = filename.Replace("zip", "json"); 11 //var aesName = filename.Replace("zip", "aes"); //作成されないため一旦コメントアウト 12 13 var json = JsonConvert.SerializeObject(_data, Formatting.Indented); 14 // JSON 文字列からエンコーディング UTF-8 でバイト列を作成 15 var bytes = Encoding.UTF8.GetBytes(json); 16 using (var ms = new MemoryStream()) 17 { 18 // メモリストリーム上にZipArchiveを作成する 19 using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true)) 20 { 21 var entry = zipArchive.CreateEntry(entryName); 22 using (var es = entry.Open()) 23 { 24 // エントリにバイナリを書き込む 25 es.Write(bytes, 0, bytes.Length); 26 } 27 } 28 // MemoryStream からバイト列を取得してファイルを作成 29 byte[] zipBytes = ms.ToArray(); 30 File.WriteAllBytes(dialog.FileName, zipBytes); 31 Encode(dialog.FileName, "C:/Users/ユーザ名/Documents/test.aes"); 32 //Encode(dialog.FileName, aesName); //出力されない 33 } 34 } 35 } 36 //AES複合化 37 private void AesOpenAsButton_Click(object sender, RoutedEventArgs e) 38 { 39 var dialog = new OpenFileDialog(); 40 if (dialog.ShowDialog().Value) 41 { 42 Decode(dialog.FileName, "C:/Users/ユーザ名/Documents/test.aes");//←こちらも可変にする予定 43 var file = dialog.FileName; 44 try 45 { 46 var reader = new StreamReader(file); 47 var json = File.ReadAllText(dialog.FileName); 48 reader.Close(); 49 _data = JsonConvert.DeserializeObject<ObservableCollection<ManagementUnitData>>(json); 50 } 51 catch (Exception error) 52 { 53 if (error.Message != null) 54 Debug.WriteLine(error.Message); 55 } 56 if (_data != null) 57 { 58 DataContext = _data; 59 } 60 } 61 } 62 //aes暗号化 63 /// <summary> 64 /// 共有キー 65 /// </summary> 66 private const string AES_KEY = "-SENJU MURAMASA-"; 67 /// <summary> 68 /// バッファサイズ 69 /// </summary> 70 private const int BUFFER_SIZE = 1024 * 4; 71 /// <summary> 72 /// 共有キービットサイズ 73 /// </summary> 74 private const int KEY_SIZE = 128; 75 /// <summary> 76 /// 暗号操作のビットサイズ 77 /// </summary> 78 private const int BLOCK_SIZE = 128; 79 /// <summary> 80 /// 暗号化 81 /// </summary> 82 /// <param name="src">入力ファイルパス</param> 83 /// <param name="dst">出力ファイルパス</param> 84 static public void Encode(string src, string dst) 85 { 86 //aes暗号化 87 using (AesManaged aes = new AesManaged()) 88 { 89 //AESインスタンスのパラメータ設定 90 aes.KeySize = KEY_SIZE; 91 aes.BlockSize = BLOCK_SIZE; 92 aes.Mode = CipherMode.CBC; 93 aes.Key = Encoding.UTF8.GetBytes(AES_KEY); 94 //初期ベクターの生成 95 aes.GenerateIV(); 96 //暗号化オブジェクトの生成 97 ICryptoTransform ct = aes.CreateEncryptor(aes.Key, aes.IV); 98 //出力ファイルストリーム 99 using (FileStream outFs = new FileStream(dst, FileMode.Create, FileAccess.Write)) 100 { 101 //初期ベクター書き込み 102 outFs.Write(aes.IV, 0, aes.IV.Length); 103 //暗号変換のストリーム(暗号化) 104 using (CryptoStream cs = new CryptoStream(outFs, ct , CryptoStreamMode.Write)) 105 { 106 //Deflateアルゴリズムを使用したストリーム(圧縮) 107 using (DeflateStream ds = new DeflateStream(cs, CompressionMode.Compress)) 108 { 109 //入力ファイルストリーム 110 using (FileStream inFs = new FileStream(src, FileMode.Open, FileAccess.Read)) 111 { 112 byte[] buf = new byte[BUFFER_SIZE]; 113 for(int size = inFs.Read(buf, 0, buf.Length); size>0; size = inFs.Read(buf, 0, buf.Length)) 114 { 115 //出力ファイルへの書き込み 116 ds.Write(buf, 0, size); 117 } 118 } 119 } 120 } 121 } 122 } 123 } 124 /// <summary> 125 /// 複合化 126 /// </summary> 127 /// <param name="src">入力ファイルパス</param> 128 /// <param name="dst">出力ファイルパス</param> 129 static public void Decode(string src, string dst) 130 { 131 // 高度暗号化標準(AES) 132 using (AesManaged aes = new AesManaged()) 133 { 134 // AESインスタンスのパラメータ設定 135 aes.KeySize = KEY_SIZE; 136 aes.BlockSize = BLOCK_SIZE; 137 aes.Mode = CipherMode.CBC; 138 aes.Key = Encoding.UTF8.GetBytes(AES_KEY); 139 // 入力ファイルストリーム 140 using (FileStream inFs = new FileStream(src, FileMode.Open, FileAccess.Read)) 141 { 142 // 初期化ベクター(IV)読込 143 byte[] iv = new byte[aes.IV.Length]; 144 inFs.Read(iv, 0, iv.Length); 145 aes.IV = iv; 146 // 複合化オブジェクト生成 147 ICryptoTransform ct = aes.CreateDecryptor(aes.Key, aes.IV); 148 // 暗号変換のストリーム(複合化) 149 using (CryptoStream cs = new CryptoStream(inFs, ct, CryptoStreamMode.Read)) 150 { 151 // Deflateアルゴリズムを使用したストリーム(圧縮解除) 152 using (DeflateStream ds = new DeflateStream(cs, CompressionMode.Decompress)) 153 { 154 // 出力ファイルストリーム 155 using (FileStream outFs = new FileStream(dst, FileMode.Create, FileAccess.Write)) 156 { 157 // 複合化した結果を書き込む 158 byte[] buf = new byte[BUFFER_SIZE]; 159 for (int size = ds.Read(buf, 0, buf.Length); size > 0; size = ds.Read(buf, 0, buf.Length)) 160 { 161 outFs.Write(buf, 0, size); 162 } 163 } 164 } 165 } 166 } 167 } 168 }
tranokado👍を押しています

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

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

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

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

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

Zuishin

2022/06/22 03:04 編集

> "C:/Users/Documents/test.aes" エスケープしてませんが、これで > →問題なくtestのaesファイルが作成される(ファイル名が可変ではないため要修正) なのでしょうか? まあ本題はディレクトリ名部分をなぜか削除しているところだと思いますが。
dodox86

2022/06/22 03:10

提示のコードが > var entryName = filename.Replace("zip", "json"); > //var aesName = filename.Replace("zip", "aes"); //作成されないため一旦コメントアウト ... > var entry = zipArchive.CreateEntry(entryName); ... > Encode(dialog.FileName, "C:/Users/Documents/test.aes"); > //Encode(dialog.FileName, aesName); //出力されない などとなっていて、ところどころ利用している変数名が合致していないような気がします。 確認用に変更しているだけかもしれませんが、実はそこを間違っていた、なんてことはないですか。
gontya

2022/06/22 03:34

> まあ本題はディレクトリ名部分をなぜか削除しているところだと思いますが。 仰る通り、ディレクトリを一部消去しておりました。(コード上では入っています。) 下記を編集し追加させていただきます。 "C:/Users/ユーザ名/Documents/test.aes"
Zuishin

2022/06/22 03:43 編集

そうではなく、System.IO.Path.GetFileName を使ってディレクトリ名を削除しているという意味です。 filename は結局このコードでは捨てられていますが、おそらく本番では使われているんでしょう?
Zuishin

2022/06/22 03:52

よく読んでいませんでした。entryname として zip に登録するのに使われているのでディレクトリ名は要りませんね。
gontya

2022/06/22 04:53

>Zuishinさん アドバイスいただきありがとうございます。 System.IO.Path.GetFileNameの仕様を勘違いしておりました。 ディレクトリ名を削除しないGetDirectoryName()メソッドを使用するべきでした。
dekaaki

2022/06/22 09:45

ちょっと補足です。 回答者さんのソースで拡張子を変更したいことは分かるのですが、単純な置換を使用すると"zip"という文字が含まれるファイル名(例えばZipper.zip)を選択された場合に誤った変換になると思います。 拡張子の変換メソッドが用意されてますのでそちらを使用する方がいいと思います。 https://dobon.net/vb/dotnet/file/changeextension.html
gontya

2022/06/23 04:22 編集

>dekaakiさん そうですね、汎用的な形にするのであればこちらの方が有効ですね。 補足ありがとうございます!
guest

回答2

0

ベストアンサー

全体的にやってることがメチャクチャという感じがするのですが? そこはとりあえず置いといて・・・

ファイルは作成できているけど自分の期待しているフォルダに無いので見つけられないだけだと思います。

Encode(dialog.FileName, "C:/Users/ユーザ名/Documents/test.aes");

これは第 2 引数にフルパスを設定しているので、設定した通りのパスに作成されるはずです。

Encode(dialog.FileName, aesName); //出力されない

こちらは質問のコードの、

var filename = System.IO.Path.GetFileName(dialog.FileName);
var aesName = filename.Replace("zip", "aes");

で aesName が "test.aes" のようになるので、質問者さんが期待している dialog.FileName で指定されるフォルダではなくて、アプリの実行フォルダにファイルが作成されるはずです。

前のスレッド https://teratail.com/questions/319hxpttp0w7nb でも言いましたが、パス名、ファイル名の操作、文字列の操作という基本的なことの知識が足りないと思います。勉強して話が通じる程度には知識を得てください。

投稿2022/06/22 04:24

編集2022/06/22 04:27
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

gontya

2022/06/22 04:51

話が通じないと言われてしまったら議論の余地がなくなってしまいますね。 申し訳ないです。学習が足りてないことは自覚しているのでもっと知識を付けてからこのようなツールを使用させていただこうかと思います。 また、回答のほどありがとうございます。 System.IO.Path.GetFileNameメソッドを使用するのが誤りでしたね。 ファイルパス全体を取得できるものと勘違いしておりました。 GetDirectoryName()メソッドを使用すればうまくいきそうなのでこちらを試させていただきます。
退会済みユーザー

退会済みユーザー

2022/06/22 05:19

> GetDirectoryName()メソッドを使用すればうまくいきそうなのでこちらを試させていただきます。 違います。そこがパス名、ファイル名の操作、文字列の操作という基本的なことの知識が足りないところです。知識を得るために Microsoft の公式ドキュメントを読みましょう。 SaveFileDialog を使ってどのようにできるかと言うと、dialog.FileName で例えば "C:/Users/ユーザ名/Documents/test.zip" という文字列が取得できたとすると、その拡張子だけを .zip から .aes に代えてそのパスでファイルを作るということになるはずです。具体的には以下のようにします(拡張子以外には zip という文字列はないことが条件)。 var aesName = dialog.FileName.Replace("zip", "aes"); 上のコードで aesName には "C:/Users/ユーザ名/Documents/test.aes" が代入されるので、それを、 Encode(dialog.FileName, aesName); と設定すればユーザーが SaveFileDialog で選んだフォルダ C:/Users/ユーザ名/Documents に test.aes という名前のファイルが生成されるはずです。
gontya

2022/06/22 06:50

なるほど、新しいメソッドを使わないでも実装の幅は多くあるんですね。 あくまで文字列の操作にすることによって、ファイルアクセス権限のことを考える必要もなくなりそうですね。 ありがとうございます。勉強になりました。
退会済みユーザー

退会済みユーザー

2022/06/22 07:32

アクセス権はまた別の話かと。 このスレッドの本題は、 (1) SaveFileDialog でユーザーが選んだパス (dialog.FileName) に zip ファイルを作成 (2) 作成した zip ファイルを読んできてそれを暗号化し、同じパスで拡張子だけ .aes に代えて別のファイルを作成する ・・・ということで、(2) でのパスの指定ができてなかったということですよね。 先に (1) でファイルが作成できている(=フォルダ対して必要なアクセス権がある)はずなので、(2) ではもうアクセス権の話は出てこないはずですけど?
gontya

2022/06/22 08:07

上記で述べていたGetDirectoryNameメソッドの話です。
退会済みユーザー

退会済みユーザー

2022/06/22 09:01

> 上記で述べていたGetDirectoryNameメソッドの話です。 GetDirectoryName メソッドをどのように使うつもりだったのか分かりませんが、少なくとも今回のケースでは出番はないはずです。 無理やり出番を作って、例えば dialog.FileName からディレクトリ名を取得して、別途作成するファイル名と連結してパスを組み立てるということはあるかもしれませんが、やはりアクセス権は関係ないはずです。先に zip ファイルが作成できれば、そのディレクトリにはアクセス権はあるはずなので。
guest

0

まずはその2番の方法でのファイル名を表示させてみよう
ファイル名では許されない文字とかフォーマットになってませんか

投稿2022/06/22 02:57

y_waiwai

総合スコア87753

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

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

退会済みユーザー

退会済みユーザー

2022/06/22 04:32

回答でないことを回答欄に書くのは止めましょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問