C#でCSVファイルを読み込んでみる(CsvHelper、TextFieldParser)

2015年02月03日
ちょっとした都合で、C#のプログラムからCSVファイルを読み込みたいと思いました。

CSV自体の標準仕様は、RFC4180に定義されています。
http://www.ietf.org/rfc/rfc4180.txt
http://www.kasai.fm/wiki/rfc4180jp

と言っても、カテゴリが「Informational」ですので、標準というよりは事実上のデファクトだから情報を周知する、という位置づけのRFCのようです。

この仕様を真面目に実装するのは面倒なので、適当なライブラリを探してみました。

スポンサーサイト

TextFieldParserを試してみる


まず、.netの標準で何かあるかなと思って調べてみたところ、近いものとしてTextFieldParserというものがありました。
参考:http://www.atmarkit.co.jp/fdotnet/dotnettips/487csvparser/csvparser.html

早速、使ってみたところ、手持ちのCSVファイルでは例外が発生してしまいました。
発生した例外のメッセージ
"現在の区切り記号を使用して、行 1 を解析できません"
例えば、下記のような行を読み込むと例外が発生します。
aaa,""bbb"" xxx,"ccc"
どちらかというと、CSVファイルが悪いのですが、問題は2カラム目です。

2カラム目の意味は、「"bbb" xxx」ですが、ダブルクォーテーションを含む文字列ですので、ダブルクォーテーションの前にダブルクォーテーションを付けてエスケープしています。
これ自体はそういうルールなので、問題はありません。

ただ、本来この場合、カラム全体をダブルクォーテーションで囲んで、
aaa,"""bbb"" xxx","ccc"
とすべきですが、囲んでいないため例外が発生しているようです。

参考までにTextFieldParserを使ったソースコードも貼っておきます。
TextFieldParser parser = new TextFieldParser(path, System.Text.Encoding.GetEncoding("euc-jp"));
parser.SetDelimiters(",");

while (!parser.EndOfData)
{
    string[] words = parser.ReadFields();
}
今回はCSVファイルを直すのも意外と厄介でしたので、別のやり方を探してみました。

CsvHelperを試してみる


とりあえず、NuGetでライブラリを探してみました。
Visual Studioのメニューの「ツール」→「NuGetパッケージマネージャー」→「ソリューションのNuGetパッケージの管理」から、「csv」で検索するといくつか出てきました。

一番上に表示されたCsvHelperの説明を読むと、CSVの読み書きやオブジェクトへのマッピングができるっぽいことが書かれているので、これを「インストール」してみました。

使い方はCsvHelperの解説ページに詳しく書かれていて、適当に使ってみたらあっさり使えました。
http://joshclose.github.io/CsvHelper/

で、例の問題になっていた行ですが…、無事、読み込めてしまいました。

今回は、オブジェクトへのマッピングは必要なかったのですが、やってみたら簡単に使えてしまったので、ソースコードを載せておきます。(実際のコードから少しいじっています)

オブジェクトとマッピングの定義
class MyClass
{
    public string Id { get; set; }
    public string Name { get; set; }
}

class MyClassMap : CsvClassMap<MyClass>
{
    public MyClassMap()
    {
        Map(m => m.Id).Index(0);
        Map(m => m.Name).Index(11);
    }
}

読み込み
CsvParser parser = new CsvParser(new StreamReader(path, Encoding.GetEncoding("euc-jp")));
parser.Configuration.HasHeaderRecord = false;  // ヘッダ行は無い
parser.Configuration.RegisterClassMap<MyClassMap>();

CsvReader reader = new CsvReader(parser);
List<MyClass> data = reader.GetRecords<MyClass>().ToList();

最後に


この記事を書いた後で他のサイトも確認していたら、下記のサイト様と内容が丸かぶりなのでどうしようかと思いました。が、ほんの少しですが追加の情報もあるし、もったいないので、そのまま掲載しました。
http://dany1468.hatenablog.com/entry/2013/07/15/175319

追記
CsvHelperのライセンスについては、 Microsoft Public License (Ms-PL)について調べてみる: 黄昏のスペシャルパンダのブログ の記事もご参照ください。


スポンサーサイト

posted at 05:00 | Comment(0) | プログラミング
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

×

この広告は180日以上新しい記事の投稿がないブログに表示されております。