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

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

Microsoft.VisualBasic.FileIO.TextFieldParser

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

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

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

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

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

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

(回答終了)


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

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


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

  1. using Microsoft.VisualBasic.FileIO;

コードの本体:

  1. string[] csvText = File.ReadAllLines(path);
  2.  
  3. var sr = new System.IO.StringReader(string.Join(Environment.NewLine, csvText));
  4. using (var pa = new TextFieldParser(sr))
  5. {
  6. pa.TextFieldType = FieldType.Delimited;
  7. pa.Delimiters = new string[] { "," };
  8.  
  9. // タイトル行
  10. string[] title;
  11. if (!pa.EndOfData)
  12. {
  13. title = pa.ReadFields();
  14. }
  15.  
  16. // データ行
  17. while (!pa.EndOfData)
  18. {
  19. var a = pa.ReadFields();
  20. // a[0] から a[N] までに各列の内容がはいっている
  21. }
  22. pa.Close();
  23. }

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

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

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

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

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

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

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

  1. const string dummyText = "🌼🌼🌼"; // 置き換えテキスト
  2. string[] csvText = File.ReadAllLines(path);
  3. for (int i = 0; i < csvText.Length; i++)
  4. {
  5. if (csvText[i] == "")
  6. {
  7. csvText[i] = dummyText;
  8. }
  9. }
  10. var sr = new System.IO.StringReader(string.Join(Environment.NewLine, csvText));
  11.  
  12. using (var pa = new TextFieldParser(sr))
  13. {
  14. pa.TextFieldType = FieldType.Delimited;
  15. pa.Delimiters = new string[] { "," };
  16.  
  17. // タイトル行
  18. string[] title;
  19. if (!pa.EndOfData)
  20. {
  21. title = pa.ReadFields();
  22. }
  23.  
  24. // データ行
  25. while (!pa.EndOfData)
  26. {
  27. var a = pa.ReadFields();
  28. for (int i = 0; i < a.Length; i++)
  29. {
  30. a[i] = a[i].Replace(dummyText, "");
  31. }
  32. // a[0] から a[N] までに各列の内容がはいっている
  33. }
  34. pa.Close();
  35. }

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

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

コメント

このブログの人気の投稿

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