none
C# ファイル保存と読み出し時の文字化けについて。 RRS feed

  • 質問

  • Visual Studio Community 2017 Version15.7.2 を使っております。

    CSVファイルへの保存時に日本語が文字化けします。

    ネット上にはたくさんの同じ悩み、対策の記事があるのですが結果現在使用している

    自分のプログラムにどう反映してよいのかが分からずにいます。

    エンコーディングが必要とのことで下のプログラムにある

    System.IO.StreamWriter sw = new System.IO.StreamWriter(stream);

    のところに鍵がありそうなのですがネットにあるお手本を貼っても上手くいかなかったり

    エラーになったりします。

    そもそも System.IO.StreamWriter sw = new System.IO.StreamWriter(stream);

    自体も理解出来ていない状態で使用しています。

    理屈からプログラムを作成するにはスキルが全く足りず、出来れば正解から理屈を理解したいです。

    どうか何卒宜しくお願い致します。

    今は半角英数文字のみであれば問題なく保存、読み出し出来ています。

    「保存のプログラム」

            string[] save_data = new string[100];// データ格納用
            private void SAVE_Click(object sender, EventArgs e)
            {
                //// データ格納
                save_data[0] = TITLE.Text;
                for (int i = 1; i <= 20; i++) { save_data[i] = Controls[$"textBox{i}"].Text; }
                for (int i = 1; i <= 20; i++) { save_data[i+20] = Controls[$"numericUpDown{i + 15}"].Text; }
                save_data[41] = UpDown_V1.Text;
                save_data[42] = UpDown_V2.Text;
                save_data[43] = UpDown_V3.Text;
                save_data[44] = UpDown_V4.Text;
                save_data[45] = UpDown_A1.Text;
                save_data[46] = UpDown_A2.Text;
                save_data[47] = UpDown_A3.Text;
                save_data[48] = UpDown_A4.Text;
                ////// データ格納 ここまで
                SaveFileDialog sfd = new SaveFileDialog(); //SaveFileDialogクラスのインスタンスを作成
                sfd.FileName = TITLE.Text; // ファイル名の指定
                sfd.Filter = "csvファイル(*.csv)|*.csv;|すべてのファイル(*.*)|*.*";
                if (sfd.ShowDialog() == DialogResult.OK) //ダイアログを表示する
                {
                    Console.WriteLine(sfd.FileName); // 指定したファイル名の表示
                    System.IO.Stream stream;
                    stream = sfd.OpenFile();
                    if (stream != null)
                    {
                        //ファイルに書き込む
                        System.IO.StreamWriter sw = new System.IO.StreamWriter(stream);
                        for (int i = 0; i < 100; i++)
                        {
                            sw.Write(save_data[i]); sw.Write("\n");
                        }
                        //閉じる
                        sw.Close();
                        stream.Close();
                    }
                }
            }

    「読み出しのプログラム」

            private void LOAD_Click(object sender, EventArgs e)
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.RestoreDirectory = true;
                ofd.CheckFileExists = true;
                ofd.CheckPathExists = true;
                //ダイアログを表示する
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    //読み込むテキストファイル
                    string textFile = ofd.FileName;
                StreamReader sr = new StreamReader(textFile, Encoding.GetEncoding("Shift_JIS"));
                try
                {
                    ///////////////////////////////////////////////
                    for (int i = 0; i < 100; i++)// 保存時の値と同じでないとエラーが出ます。
                    {
                        string line = sr.ReadLine();
                        string[] fields = line.Split(',');
                            if (i == 0) { TITLE.Text = fields[0]; }
                            if ((i >= 1) && (i < 21)) { Controls[$"textBox{i}"].Text = fields[0]; }
                            if ((i >= 21) && (i < 41)) { Controls[$"numericUpDown{i - 5}"].Text = fields[0]; }
                            if (i == 41) { UpDown_V1.Text = fields[0]; }
                            if (i == 42) { UpDown_V2.Text = fields[0]; }
                            if (i == 43) { UpDown_V3.Text = fields[0]; }
                            if (i == 44) { UpDown_V4.Text = fields[0]; }
                            if (i == 45) { UpDown_A1.Text = fields[0]; }
                            if (i == 46) { UpDown_A2.Text = fields[0]; }
                            if (i == 47) { UpDown_A3.Text = fields[0]; }
                            if (i == 48) { UpDown_A4.Text = fields[0]; }
                        }
                }
                finally
                {
                    sr.Close();
                }
            }
        }


    2019年7月10日 6:03

回答

  • > System.IO.StreamWriter(stream,System.Text.Encoding.GetEncoding("shift_jis"));
    > としましたら出来ました。

    Shift_JIS でなければならないという事情がなければ UTF-8 を使った方がよさそうです。

    その場合 StreamWriter は最初の質問のコードのままにしておけば BOM 無し UTF-8 になるので、StreamReader の第 2 引数を UTF-8 にすれば良いはずです。
    2019年7月10日 7:53

すべての返信

    1. スタート メニューから [Windows アクセサリ] - [メモ帳] を開きます。
    2. [ファイル] - [開く] メニューから対象の csv ファイルを開く際に、ダイアログ下部にある [文字コード] を "UTF-8" に指定します。

    上記の場合、そのファイルの内容は文字化けせずに開けるのではないでしょうか。

    UTF-8 以外の文字コードを使ってファイルを読み書きしたい場合は、StreamWriter を new する際に、Encoding を指定するようにします。下記が参考になるでしょう。

    2019年7月10日 6:22
  • Shift_JIS, UTF-8, UTF-16 など何を意味するか分かりますか? もし分からなければググって調べてエンコーディングに関する基本的な知識を得てください。それからでないとここでやり取りしても話が通じないと思います。
    2019年7月10日 6:25
  • BOM が付いてないと質問にある BOM でエンコーディングを判定する StreamReader のオーバーロードでは問題があるのではないですか? 最新の Windows 10 のメモ帳では UTF-8 は BOM 無しになりますし。

    【追伸】

    魔界の仮面弁士さんのレスの 1, 2 の意味は、

    .csv ファイルは BOM 無し UTF-8 で保存されているはずなので、メモ帳で BOM 無し UTF-8 を指定して開けば文字化けせず読めるはず。

    ・・・と言うことですね。とすると、意味が理解できてなかったようで、上は的外れなレスになってしまいました、すみません。

    でも、上に言ってることは間違いないです。メモ帳で BOM 無し UTF-8 を指定して文字化けなしで開けたら、それを BOM 付 UTF-8 で保存し直せば、StreamReader(textFile, Encoding.GetEncoding("Shift_JIS")); で文字化けなしで読めると思います。

    2019年7月10日 6:33
  • System.IO.StreamWriter sw = new System.IO.StreamWriter(stream);

    のところを

    System.IO.StreamWriter sw = new System.IO.StreamWriter(stream,System.Text.Encoding.GetEncoding("shift_jis"));

    としましたら出来ました。

    皆様ありがとうございました。

    2019年7月10日 7:40
  • > System.IO.StreamWriter(stream,System.Text.Encoding.GetEncoding("shift_jis"));
    > としましたら出来ました。

    Shift_JIS でなければならないという事情がなければ UTF-8 を使った方がよさそうです。

    その場合 StreamWriter は最初の質問のコードのままにしておけば BOM 無し UTF-8 になるので、StreamReader の第 2 引数を UTF-8 にすれば良いはずです。
    2019年7月10日 7:53
  • .csv ファイルは BOM 無し UTF-8 で保存されているはずなので、メモ帳で BOM 無し UTF-8 を指定して開けば文字化けせず読めるはず。

    ・・・と言うことですね。

    はい、そういうことです。

    「元のコードだと UTF-8 で保存されることになる」ということを確認してもらってから、「別の文字コードにしたいなら Encoding を指定すれば良い」という流れの回答です。

    仮に文字コードについて不慣れな人であったとしても、文字コードを指定して開いてもらうようにすれば、意図が伝わりやすいだろうという期待を込めて。

    ただし、どの Encoding を指定すべきかは、元質問者さんが求める仕様によって変わってくるので、その点は具体的には言及せず、参考情報の URL を紹介するに留めておきました。csv でよく使われるのは、「Shift_JIS / BOM 付き UTF-8 / BOM なし UTF-8 / UTF-16LE / BOM 付き UTF-16 (リトルエンディアン)」あたりですね。

    最新の Windows 10 のメモ帳では UTF-8 は BOM 無しになりますし。

    Win10 v1903 のメモ帳だと、「自動検出 / ANSI / UTF-16 LE / UTF-16 BE / UTF-8 / UTF-8 (BOM 付き)」の 6 パターンが選べます。

    Win 2000~7 のメモ帳だと、「ANSI / Unicode / Unicode big endian / UTF-8」の 4 パターンが選べます。

    Win NT 4.0 の頃は、Unicode を使うかどうかの 2 パターンのみでした。Win 98SE は ANSI 専用。

    蛇足ですが、2000 や XP の頃のメモ帳は、"this app can break" とだけ書かれたテキストが文字化け表示されるという問題がありました。これは、BOM が無いファイルの自動判定処理に問題があったためです。

    // この 2 つは同じバイナリとなる
    byte[] bin1 = System.Text.Encoding.Unicode.GetBytes("桴獩愠灰挠湡戠敲歡");
    byte[] bin2 = System.Text.Encoding.ASCII.GetBytes("this app can break");
    Console.WriteLine( bin1.SequenceEqual(bin2) ? "一致" : "異なる" );

    ファイルの文字コードというものは、必ずしも正しく自動判定できるとは限りません(BOM 付であれば自動判定できますが)ので、プログラムからテキストファイルを読み書きする場合は、明示的に Encoding を指定することをお奨めしておきます。

    2019年7月10日 8:40
  • kinto-to-claveさん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    ご質問いただいた件につきまして、
    SurferOnWwwさんと魔界の仮面弁士さんより参考になる投稿が寄せられたようでなによりです。

    [回答としてマーク]機能は設定された投稿が後から参照しやすくなりますので、
    同じ問題でお困りの方のためにも参考になった投稿に設定いただけますと幸いです。

    お手数ですが、ご協力の程どうかよろしくお願いいたします。


    MSDN/ TechNet Community Support Haruka

    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年7月16日 2:02
    モデレータ
  • 大変遅くなり申し訳ありません。しばらく離れておりました。結果UTF-8指定で保存UTF-8指定で読み出しにしました。保存したCSVファイルを単体で開いた時に内容が読めた方がよかったからです。元々のプログラムの場合どういう形式で保存されているとかが全く解っていない状態でした。BOMとかはちょっと私には深い感じでしたが今後のハマりの時のヒントくらいになれば良いと思いました。

    大変ありがとうございました。

    2019年7月24日 1:17