C#でCSVファイルを読む手順
CSVファイルを読み込むには、以下のライブラリを使う。これが定石。
Microsoft.VisualBasic.FileIO.TextFieldParser
CSVファイルをきちんとカンマで区切りながら読んでくれる。とても便利。
❓(質問)CSVファイルは Split メソッドを使えば列ごとに分解できるのでは?
(回答)CSVファイルには、ダブルクォーテーションで囲まれたテキストもOKで、このときはSplitでカンマごとに分割しても「"」が残ってしまうのでダメです。
(例) 番号,レベル,説明 1,2,"説明1" 2,4,"説明2 詳細は***に示す"
しかも、「"」で囲まれたテキストは改行してもよいので(上の例)、これではSplitでどうにかすることはできません。
TextFieldParser は上記のケースすべてに対応して、きちんと読み込むことができます。
(回答終了)
CSVファイルを読み込むコードは以下のように書ける。ここでは以下の流れ。
- CSVファイルを全行読み込む→配列に入る
- 配列を改行を挟んで連結する→長い文字列になる
- TextFieldParserのオブジェクトを作って、文字列を引数に渡す
- TextFieldParserの読み込み設定をする→「、」区切り
- 1行目はタイトルとして読む
- 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は使えない!」と捨ててしまうのはもったいないので、ちょっと工夫して空行問題を解決してみる。アイデアは簡単で、
- 空行を何かで埋めて非空行として読ませて、あとで空行に戻す
というものです。
コードはこんな流れになる。
- CSVファイルを全行読み込む→配列に入る
- (追加)空行を花文字に置き換える
- 配列を改行を挟んで連結する→長い文字列になる
- TextFieldParserのオブジェクトを作って、文字列を引数に渡す
- TextFieldParserの読み込み設定をする→「、」区切り
- 1行目はタイトルとして読む
- 2行目以降はデータとして読む
- (追加)読み込んだ配列内に花文字があったら「""」に置き換える
置き換える何かは、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は便利なライブラリなので、使っていきましょう。
コメント
コメントを投稿