none
saveFileDialog1で書き込みopenFileDialog1で読み込むと文字化けします。 RRS feed

  • 質問

  •  

    richTextBox1に手打ちで書き込んだ文字は以下の2行です。

    てすと1
    テスト2

    書き込みプログラムは以下です。

    namespace SaveFileDialogApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                // [名前をつけて保存]ダイアログを表示します。
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    // 指定したファイル名でstreamWriterを作成します
                    StreamWriter streamWriter = new StreamWriter(saveFileDialog1.FileName);
                    // richTextBox1のTextの内容をファイルに書き込みます
                    streamWriter.Write(richTextBox1.Text);
                    // streamWriterを閉じます。
                    streamWriter.Close();
                }
            }
        }
    }

    出力結果は以下です。

    てすと1
    テスト2

    あれれ、メモ帳ですと上の2行は実際には改行が↑で区切られ1行になっています。「コピーペ」でちゃんと改行されちゃいますね。

    読み込みプログラムは以下です。

    namespace OpenFileDialogApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                // [フォルダの参照]ダイアログを表示します。
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    FileStream stream = (FileStream)openFileDialog1.OpenFile();
                    StreamReader reader = new StreamReader(stream, Encoding.Default);
                    richTextBox1.Text = reader.ReadToEnd();
            MessageBox.Show(richTextBox1.Text.ToString());
                    reader.Close();
                    stream.Close();
                }
            }
        }
    }

    richTextBox1.Textの内容が文字化けしています。
    このプログラムば添付のサンプルですので私は何もしていません。
    全く勉強になりませんねぇ。
    コード変換のプロセスなどが必要なのでしょうか?

    2009年7月31日 7:48

回答

  • 読み込みプログラムの
    Encoding.Default

    Encoding.UTF8
    に変えたらなおりました。

    メモ帳で改行して見えないのは
    メモ帳とリッチテキストボックスの
    改行コードの違いなんでしょうね。

    • 回答としてマーク 若葉 2009年8月3日 6:06
    2009年7月31日 8:21
  • 外池です。

    StreamWriterのコンストラクタで、お示し頂いたようにエンコードの指定をしなかった場合は、デフォルトでUTF-8に設定されます。StreamReaderのコンストラクターについても同様。ですので、どちらも、エンコードを指定しなければ、上手くいくはずです。

    一方で、じゃぁ、Encoding.Defaultってなんなのよ? と言うことになりますが、Encodingというクラスのメンバーのひとつの名前にすぎません。Encoding.Defaultは、OSのデフォルトのANSIコードページのエンコーディングということになっています。日本の場合ならShift-JISだったかな?

    で、StreamWriter、StreamReaderのエンコードのデフォルトとは、また、別なのよ、というオチです。


    (ホームページを再開しました)
    • 回答としてマーク 若葉 2009年8月3日 6:07
    2009年7月31日 11:03

  • StreamWriterのコンストラクタで、お示し頂いたようにエンコードの指定をしなかった場合は、デフォルトでUTF-8に設定されます。StreamReaderのコンストラクターについても同様。ですので、どちらも、エンコードを指定しなければ、上手くいくはずです。
    分かりづらいですが、クラスの説明部分に書いていますね。
    http://msdn.microsoft.com/ja-jp/library/system.io.streamreader(VS.80).aspx
    http://msdn.microsoft.com/ja-jp/library/system.io.streamwriter(VS.80).aspx

    解決法としては、どちらもエンコードを指定しないか、同じエンコードを指定するかです。(求められることは、同じエンコードに合わせること)


    一方で、じゃぁ、Encoding.Defaultってなんなのよ? と言うことになりますが、Encodingというクラスのメンバーのひとつの名前にすぎません。Encoding.Defaultは、OSのデフォルトのANSIコードページのエンコーディングということになっています。日本の場合ならShift-JISだったかな?
    ANSI になることは Encoding.Default の説明にありますね。
    http://msdn.microsoft.com/ja-jp/library/system.text.encoding.default(VS.80).aspx

    日本語 Windows では Shift-JIS になります。その対応付けを公的に言及したドキュメントがどれかまでは自身がありませんが…。

    # http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx か?
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク 若葉 2009年8月3日 6:07
    2009年7月31日 14:54
    モデレータ

すべての返信

  • 読み込みプログラムの
    Encoding.Default

    Encoding.UTF8
    に変えたらなおりました。

    メモ帳で改行して見えないのは
    メモ帳とリッチテキストボックスの
    改行コードの違いなんでしょうね。

    • 回答としてマーク 若葉 2009年8月3日 6:06
    2009年7月31日 8:21
  • 外池です。

    StreamWriterのコンストラクタで、お示し頂いたようにエンコードの指定をしなかった場合は、デフォルトでUTF-8に設定されます。StreamReaderのコンストラクターについても同様。ですので、どちらも、エンコードを指定しなければ、上手くいくはずです。

    一方で、じゃぁ、Encoding.Defaultってなんなのよ? と言うことになりますが、Encodingというクラスのメンバーのひとつの名前にすぎません。Encoding.Defaultは、OSのデフォルトのANSIコードページのエンコーディングということになっています。日本の場合ならShift-JISだったかな?

    で、StreamWriter、StreamReaderのエンコードのデフォルトとは、また、別なのよ、というオチです。


    (ホームページを再開しました)
    • 回答としてマーク 若葉 2009年8月3日 6:07
    2009年7月31日 11:03

  • StreamWriterのコンストラクタで、お示し頂いたようにエンコードの指定をしなかった場合は、デフォルトでUTF-8に設定されます。StreamReaderのコンストラクターについても同様。ですので、どちらも、エンコードを指定しなければ、上手くいくはずです。
    分かりづらいですが、クラスの説明部分に書いていますね。
    http://msdn.microsoft.com/ja-jp/library/system.io.streamreader(VS.80).aspx
    http://msdn.microsoft.com/ja-jp/library/system.io.streamwriter(VS.80).aspx

    解決法としては、どちらもエンコードを指定しないか、同じエンコードを指定するかです。(求められることは、同じエンコードに合わせること)


    一方で、じゃぁ、Encoding.Defaultってなんなのよ? と言うことになりますが、Encodingというクラスのメンバーのひとつの名前にすぎません。Encoding.Defaultは、OSのデフォルトのANSIコードページのエンコーディングということになっています。日本の場合ならShift-JISだったかな?
    ANSI になることは Encoding.Default の説明にありますね。
    http://msdn.microsoft.com/ja-jp/library/system.text.encoding.default(VS.80).aspx

    日本語 Windows では Shift-JIS になります。その対応付けを公的に言及したドキュメントがどれかまでは自身がありませんが…。

    # http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx か?
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク 若葉 2009年8月3日 6:07
    2009年7月31日 14:54
    モデレータ


  • あんにんごさん、外池さん、Azuleanさん

    ありがとうございます。
    何となく分かってきました。
    メモ帳のデホルト値がANSIコードになっているのでちょっとへんてこな約束事になっているのではないでしょうか。

    書き出し側、
    // Write&Readの場合どちらもエンコードを指定しないか、同じエンコードを指定するかが基本です。                              
    //streamWriter.Write(richTextBox1.Text,Encoding.Default);  // 漢字コードをDefaultに指定した場合UTF-8で書き出される。                                   
                                                                             // よってDefaultの場合読み込み時は漢字コードを指定しないこと。
    //streamWriter.Write(richTextBox1.Text, Encoding.UTF8);    // 漢字コードをUTF-8に指定する場合。                                  
    streamWriter.Write(richTextBox1.Text);                         // 漢字コードを指定しない場合UTF-8で書き出される。
             
    読み込み側、                                                                                                                        
    // Write&Readの場合どちらもエンコードを指定しないか、同じエンコードを指定するかが基本です。                              
    //StreamReader reader = new StreamReader(stream, Encoding.Default);  // 漢字コードをDefaultに指定する場合。                          
                                                                                            // ただし、Defaultの場合Shift-JISとして読み込まれます。
    //StreamReader reader = new StreamReader(stream,Encoding.UTF8);      // 漢字コードをUTF-8に指定する場合。                        
    StreamReader reader = new StreamReader(stream);                          // 漢字コードを指定しない場合。

    1ユーザーとしてはEncoding.Defaultはどちらかに統一して欲しいと思います。
    上記の記述例ですとメモ帳での書き出し時にUTF-8に設定して...という意識を常に要求されます。
    こんなことが出来ると便利だと思うが?
    Set Encoding.Default = Shift-JIS;                      // Encoding.DefaultをShift-JISに設定して
    StreamReader reader = new StreamReader(stream);  // 省略した場合はDefaulta値を優先する。

    2009年8月3日 6:06
  • 外池です・・・。整理されたのでしょうけど、なんか、全然整理できてないような気がします。

    「書き出し側」について、いきなりですが、streamWriterは、これは、変数名ですよね? で、すでにインスタンスが作ってあるわけですよね? それに対して、Wirteメソッドするときは、もう、エンコードを指定するには遅すぎます。(ちなみに、StreamWriterで、Readすることはありません。)

    インスタンスを作るとき(newするとき)にエンコードの指定をします。

    StreamWriterのインスタンスを作成する際にエンコードをEncoding.Defaultに指定すると、UTF-8では書き出されません。日本語環境の場合ですと、Shift-JISです。エンコードをEncoding.UTF8に指定するとUTF-8で書き出されます。エンコードを指定しないと、やはり、UTF-8になります。

    「読み込み側」は、概ねあっているかと思います。(ただし、StreamReaderで、Writeすることはありません。)

    で、よく比較して欲しいのですが、「書き出し側」(StreamWriter)と「読み込み側」(StreamReader)のインスタンス作成時の設定において、Encoding.Defaultの解釈は、ちゃんと統一されています。日本語環境なら、先に書いたように、どちらもShift-JISです。

    緻密な調査と整理をお願いします。
    (ホームページを再開しました)
    • 編集済み 外池 2009年8月3日 8:00
    2009年8月3日 7:54
  •  

    外池さん、

    お世話になります。
    コードの前後を省略したのでこちらの意図が伝わらなかったようです。
    streamWriterは変数名です。
    書き出し側プログラムの例ではEncoding.Defaultを指定してもUTF-8で書き出されています。

    msdnにはインスタンスを作るとき(newするとき)の記述例が
    StreamWriter swFromFileStreamDefaultEnc = new System.IO.StreamWriter(fs, System.Text.Encoding.Default);
    となっていますがSystem.Text.Encoding.Defaultを以下のプログラムに記述するとエラーになります。

    このような場合の正しい記述はどの様になるのでしょうか?

    以下は書き出し側プログラムです。

    namespace SaveFileDialogApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                // [名前をつけて保存]ダイアログを表示します。
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    // 指定したファイル名でstreamWriterを作成します。
                    StreamWriter streamWriter = new StreamWriter(saveFileDialog1.FileName);

                    // richTextBox1のTextの内容をファイルに書き込みます。
                    // Write後Readの場合どちらもエンコードを指定しないか、同じエンコードを指定するかが基本です。
                    streamWriter.Write(richTextBox1.Text,Encoding.Default);    // 漢字コードをDefaultに指定した場合UTF-8で書き出される。
                                                  // よってDefaultの場合読み込み時は漢字コードを指定しないこと。


                    // streamWriterを閉じます。
                    streamWriter.Close();
                }
            }
        }
    }

    2009年8月5日 0:42
  • 外池です。

    「StreamWriter streamWriter = new StreamWriter(saveFileDialog1.FileName);」の行でEncoding.Defaultを指定しようとしてもエラーになるから、指定していないと・・・。若葉さんの「態度」は理解できました。

    まず、Shift-JISで書き出すことを意図されているわけですよね? ならば、エラーが出る理由を別途調べて解決して頂き、是非、この時点でEncoding.Defaultを指定するようにしてください。指定する機能はありますから。そうでないと、後で出てくるstreamWriterによる書き出しは、すべて、UTF-8になります。

    次に、「streamWriter.Write(richTextBox1.Text,Encoding.Default);」というような形で、エンコードを指定する機能はありません。なぜ、これでエラーが出ないのかとちょっと不思議なぐらいですが、ドキュメントを調べてみると、最初の引数に文字列型、2番目の引数にオブジェクト型をとるWriteメソッドがありますね。なので、エラーにはなりません。で、このメソッドは基本的に、2番目の引数の内容を出力するもののようです。出力する際のフォーマットを最初の引数で指定できるようになっているようです。なんとなくそれっぽく動いているでしょうけれども、上述のとおり若葉さんが意図する機能を実現するものではないので、使ってはいけません。「streamWriter.Write(richTextBox1.Text);」とすべきです。

    -------------------

    繰り返しになりますが、最初に書いたように、インスタンスを作成する際にEncoding.Defaultを指定するようにしてください。エラーが出る理由は、指定する機能が無いからではなく、若葉さんの書き方のお作法が何か間違っているからです。お作法の何が間違っているかは、みっちり、ドキュメントを読んで調べてください。

    ヒントは、
    http://msdn.microsoft.com/ja-jp/library/system.io.streamwriter.streamwriter.aspx

    とにかく、ドキュメントを読まずに「あぁ、こんな機能はあって当然だから、適当に単語を並べて書いてみよう」とプログラム書き下しても、まず、絶対に意図したとおりには動きません(コンパイル時にエラーになるか、実行させてみてエラーになるか、エラーにならなくても変な挙動を示すか)。相手が人間なら自然言語を理解できる能力がありますが、現在のパソコンを相手だと無理です。

    まず、機能の有無、その機能を使うための厳密な文法の調査が必要です。2回目になりますが「緻密な調査」をお願いします。


    (ホームページを再開しました)
    2009年8月5日 2:20


  • 外池さん、
    ありがとうございます。
    Encoding指定をする時は何やら間に上書きの有無を指定するコードが無いと漢字コードは指定できない。
    System.IO.StreamWriter textname = System.IO.StreamWriter(path, true/false, Encoding);
    ウムウム、するとこの違いは何だ!!
    StreamWriter swFromFileStreamDefaultEnc =  new System.IO.StreamWriter(fs, System.Text.Encoding.Default);
    msdnの中を色々と探してみましたが説明されている箇所を見つけ出すことができませんでした。
    まあ、いいか。
    今までの疑問に対する答えがちゃん記載されている書籍を探し出すことが次の一歩になるであろう。
    これからも、ご指導のほどよろしくお願いいたします。

    以下が前記のコードの訂正箇所です。
                    // 指定したファイル名でstreamWriterを作成します
                    // Write&Readの場合どちらもエンコードを指定しないか、同じエンコードを指定するかが基本です。
                    Encoding s_sjis = Encoding.GetEncoding("Shift_JIS");       // 漢字コードをShift_JISに設定します。
                    StreamWriter s_text = new StreamWriter(saveFileDialog1.FileName, false, s_sjis);   // s_sjisはEncoding.Defaultと結果は同じ。

                    // richTextBox1のTextの内容をファイルに書き込みます
                    s_text.Write(richTextBox1.Text);                    

                    // streamWriterを閉じます。
                    s_text.Close();

    2009年8月5日 6:51
  • Encoding指定をする時は何やら間に上書きの有無を指定するコードが無いと漢字コードは指定できない。
    System.IO.StreamWriter textname = System.IO.StreamWriter(path, true/false, Encoding);
    ウムウム、するとこの違いは何だ!!
    StreamWriter swFromFileStreamDefaultEnc =  new System.IO.StreamWriter(fs, System.Text.Encoding.Default);
    msdnの中を色々と探してみましたが説明されている箇所を見つけ出すことができませんでした。
    コンストラクタのオーバーロード一覧はご覧になりましたか?
    http://msdn.microsoft.com/ja-jp/library/system.io.streamreader.streamreader.aspx
    http://msdn.microsoft.com/ja-jp/library/system.io.streamwriter.streamwriter.aspx

    第 1 引数に Stream を渡すパターンであれば、第 2 引数に Encoding を渡すことができます。
    また、StreamReader は読み取りが目的であるため、ファイルの追記・上書きを指定する必要がないため、第 1 引数にファイル名を渡すパターンでも、第 2 引数で Encoding を指定することができます。

    今までの疑問に対する答えがちゃん記載されている書籍を探し出すことが次の一歩になるであろう。
    ピンポイントでその疑問を答える書籍は、残念ですが、存在しないと思っています。
    基本的な仕組み、考え方が分かってくれば、想像・推測できるようになってくる所と言えるかもしれません。
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年8月5日 14:25
    モデレータ


  • Azuleanさん

    ありがとうございます。
    ちょっと昔を思い出しました。ファイルを開く前には必ずファイルの定義をしていました。
    手元の書籍にはFileStreamでファイルの定義などしていないのでC#には必要ないのか、と思っていました。
    本屋さん回りで読んでいてもこの様なことは書いてなかったと記憶しています。「場合によってはファイルの定義は省略可なのでしょう。」
    ファイルの定義
    FileStream fs = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.None);
    ファイルのOpen
    StreamWriter swFromFileStreamDefaultEnc = new System.IO.StreamWriter(fs, System.Text.Encoding.Default);

    以下、FileStreamの列挙体との関係を学ぶ為わざとめんどくさいコードに変更しいます。
            private void button1_Click(object sender, EventArgs e)
            {
                string s_path = @"C:\Documents and Settings\global2\My Documents\root\test-2.txt";
                // 指定したファイル名でFileStreamを作成します
                DialogResult s_dr = MessageBox.Show("指定のファイル" + s_path + "は既に存在します。 上書きしてよいですか?", "上書き確認?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (s_dr == DialogResult.Yes)
                {
                    // Write&Readの場合どちらもエンコードを指定しないか、同じエンコードを指定するかが基本です。
                    FileStream s_fs = new FileStream(s_path, FileMode.Create, FileAccess.Write, FileShare.None);
                    Encoding s_sjis = Encoding.GetEncoding("Shift_JIS");     // 漢字コードをShift_JISに設定します。
                    StreamWriter s_text = new StreamWriter(s_fs, s_sjis);    // s_sjisはEncoding.Defaultと結果は同じ。
                    // richTextBox1のTextの内容をファイルに書き込みます
                    s_text.Write(richTextBox1.Text);

                    // streamWriterを閉じます。
                    s_text.Close();
                    MessageBox.Show("上書きしました。");
                }
                else
                {
                    MessageBox.Show("書き出されていません。");
                    return;
                }
            }

    C#って深いですね。前の定義次第で次の定義の因数の定義文法が変化する。。。
    今後の問題はShift_JISで出来てしまっているデータですね。
    C#の基本コードはUTF-8みたいだから
                StreamWriter s_text = File.CreateText(s_path);
                s_text.Close();
    といったちょっとした事でもコードの違いで苦労が予想される。
    これから学ぼうとするデータベースのフィールド値のコードでも同じような苦労が出てくるだろう。

    2009年8月6日 7:26
  • C#って深いですね。前の定義次第で次の定義の因数の定義文法が変化する。。。
    「因数」ではなく「引数」だと思いますが、「前の定義次第で次の定義の引数が変わる」わけではありません。
    提供されているメソッド、コンストラクタから自分が使いたいものを選び、組み合わせることになります。

    なお、FileStream や StreamReader、StreamWriter は C# 独自のものではなく、.NET Framework のクラスライブラリで提供されているものです。
    これらのクラスは VB.NET からも同じように利用できます。
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年8月6日 14:39
    モデレータ