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は便利なライブラリなので、使っていきましょう。
コメント
コメントを投稿