C#でCSVファイルを読む手順

CSVファイルを読み込むには、以下のライブラリを使う。これが定石。

Microsoft.VisualBasic.FileIO.TextFieldParser

CSVファイルをきちんとカンマで区切りながら読んでくれる。とても便利。

❓(質問)CSVファイルは Split メソッドを使えば列ごとに分解できるのでは?

(回答)CSVファイルには、ダブルクォーテーションで囲まれたテキストもOKで、このときはSplitでカンマごとに分割しても「"」が残ってしまうのでダメです。

 (例)
番号,レベル,説明
1,2,"説明1"
2,4,"説明2
詳細は***に示す"

しかも、「"」で囲まれたテキストは改行してもよいので(上の例)、これではSplitでどうにかすることはできません。

 TextFieldParser は上記のケースすべてに対応して、きちんと読み込むことができます。

(回答終了)


CSVファイルを読み込むコードは以下のように書ける。ここでは以下の流れ。

  1. CSVファイルを全行読み込む→配列に入る
  2. 配列を改行を挟んで連結する→長い文字列になる
  3. TextFieldParserのオブジェクトを作って、文字列を引数に渡す
  4. TextFieldParserの読み込み設定をする→「、」区切り
  5. 1行目はタイトルとして読む
  6. 2行目以降はデータとして読む


ファイルのの先頭に using を追加

using Microsoft.VisualBasic.FileIO;

コードの本体:

            string[] csvText = File.ReadAllLines(path);

            var sr = new System.IO.StringReader(string.Join(Environment.NewLine, csvText));
            using (var pa = new TextFieldParser(sr))
            {
                pa.TextFieldType = FieldType.Delimited;
                pa.Delimiters = new string[] { "," };

                // タイトル行
                string[] title;
                if (!pa.EndOfData)
                {
                    title = pa.ReadFields();
                }

                // データ行
                while (!pa.EndOfData)
                {
                    var a = pa.ReadFields();
                    // a[0] から a[N] までに各列の内容がはいっている
                }
                pa.Close();
            }

(質問)TextFieldParserは空行を読んでくれないので困るのだが?

(回答)そうですね、以下のようなCSVファイルの場合、①の空行と②の空行もTextFieldParserは読んでくれません(読み飛ばされる)。
 (例)
番号,レベル,説明
1,2,"説明1"
         ←①空行
2,4,"説明2 
         ←②空行(「"」の中なので読み飛ばされるのは問題)
詳細は***に示す"

 とはいえ、「TextFieldParserは使えない!」と捨ててしまうのはもったいないので、ちょっと工夫して空行問題を解決してみる。アイデアは簡単で、

  • 空行を何かで埋めて非空行として読ませて、あとで空行に戻す
というものです。

コードはこんな流れになる。

  1. CSVファイルを全行読み込む→配列に入る
  2. (追加)空行を花文字に置き換える
  3. 配列を改行を挟んで連結する→長い文字列になる
  4. TextFieldParserのオブジェクトを作って、文字列を引数に渡す
  5. TextFieldParserの読み込み設定をする→「、」区切り
  6. 1行目はタイトルとして読む
  7. 2行目以降はデータとして読む
  8. (追加)読み込んだ配列内に花文字があったら「""」に置き換える

置き換える何かは、CSVファイルの中で使われていないテキストということで、ここでは花文字3つとしてみた。それぞれに応じて変えてもらえればOK。

           const string dummyText = "🌼🌼🌼";       // 置き換えテキスト
            string[] csvText = File.ReadAllLines(path);
            for (int i = 0; i < csvText.Length; i++)
            {
                if (csvText[i] == "")
                {
                    csvText[i] = dummyText;
                }
            }
            var sr = new System.IO.StringReader(string.Join(Environment.NewLine, csvText));

            using (var pa = new TextFieldParser(sr))
            {
                pa.TextFieldType = FieldType.Delimited;
                pa.Delimiters = new string[] { "," };

                // タイトル行
                string[] title;
                if (!pa.EndOfData)
                {
                    title = pa.ReadFields();
                }

                // データ行
                while (!pa.EndOfData)
                {
                    var a = pa.ReadFields();
                    for (int i = 0; i < a.Length; i++)
                    {
                        a[i] = a[i].Replace(dummyText, "");
                    }
                    // a[0] から a[N] までに各列の内容がはいっている
                }
                pa.Close();
            }
            

これでOK。ただし、さすがにタイトル行には空行は無いだろうということで、そこは未対策。

TextFieldParserは便利なライブラリなので、使っていきましょう。

コメント

このブログの人気の投稿

varchar をデータ型 numeric に変換中に、算術オーバーフロー エラーが発生しました。