概要
C#でCSVファイルを1行ずつ処理したい時に少しハマったので、備忘録的にを残しておきます。
StreamReaderを利用する方法
これはググって最初に出てきた方法です。
C#でファイルを読み込む際はStreamReaderを使うのが普通のようです。
1行ずつ文字列として読み込んでカンマでsplitすれば要素を取得できます。
Program.CSと同じ階層に以下のようなCSVファイルがあるとします。
input.csv
A1,A2,A2
B1,B2,B3
Program.CS
using System;
using System.IO;
namespace TestReadingCsv
{
class Program
{
static void Main(string[] args)
{
using (StreamReader reader = new StreamReader(@"..\..\..\input.csv"))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
string[] values = line.Split(',');
foreach (string value in values)
Console.WriteLine(value);
}
}
}
}
}
結果
A1
A2
A2
B1
B2
B3
問題点
しかし、この方法だと要素内にカンマや改行が含まれている時に期待する結果にはなりません。
また、CSVがダブルクォートで囲まれている形式だった場合にいちいち取り除く必要があり不便です。
ましてや、行によってダブルクォートが有ったり無かったりしたら面倒極まりないでしょう。
input.csv
A1,"カンマ,が含まれた行",A2
"B1","改行
が含まれた行","B3"
Program.CS
using System;
using System.IO;
namespace TestReadingCsv
{
class Program
{
static void Main(string[] args)
{
using (StreamReader reader = new StreamReader(@"..\..\..\input.csv"))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
string[] values = line.Split(',');
int i = 1;
foreach (string value in values)
Console.WriteLine(string.Format("{0}: {1}", i++, value));
}
}
}
}
}
結果
1: A1
2: "カンマ
3: が含まれた行"
4: A2
1: "B1"
2: "改行
1: が含まれた行"
2: "B3"
TextFieldParserを利用する方法
このようなケースにぴったりのクラスがありました。それがTextFieldParserです。
要素内のカンマや改行に対応しています。また、ダブルクォートの有無が混在していても問題ありません。
(こっちを先に見つけていれば困ることもなかったのに・・・)
Program.CS
using System;
using Microsoft.VisualBasic.FileIO;
namespace TestReadingCsv
{
class Program
{
static void Main(string[] args)
{
using (TextFieldParser txtParser = new TextFieldParser(@"..\..\..\input.csv"))
{
txtParser.SetDelimiters(",");
while (!txtParser.EndOfData)
{
string[] values = txtParser.ReadFields();
int i = 1;
foreach (string value in values)
Console.WriteLine(string.Format("{0}: {1}", i++, value));
}
}
}
}
}
結果
1: A1
2: カンマ,が含まれた行
3: A2
1: B1
2: 改行
が含まれた行
3: B3
まさにこれって感じですね。
区切り文字をタブ文字にすればTSVにも対応できます。
その他にもいくつか設定値があるので、うまく使いこなせばCSV以外のフォーマットでも使えそうです。