C# で CSV の生成
.NET で CSV を読み書きするには、一つの方法として、”TextFieldParser” を利用する方法があります。
[C#][VB.NET] TextFieldParserでCSV(TSV)ファイルを読み込む方法
これは、Microsoft製のライブラリですが、オープンソースのライブラリを使用する方法もあります。例えば、CsvHelper というライブラリが有名なのでこれを使ってみます。ソースはリンクからどうぞ。
今回はCSVの生成、書き込みの方法をまとめてみます。
CsvHelperとは
Document
使い方は上記リンクで確認できます。
Install
まずはNugetからパッケージをインストールします。
Install-Package CsvHelper
基本
CsvHelperは、クラスのデータをCSVの列フィールドへマップしたり、その逆にCSVの列フィールドをクラスの各プロパティにマップしてくれます。マッピングを管理するクラスを定義すれば、どの列をプロパティ対応させるかや、どのプロパティをどの列順に出力するかなどを簡単に管理できます。
CSV書き込み
CSVを生成するには、CsvWriterを使います。コンストラクタに、”TextWriter” を渡します
。今回の例では適当なファイルに書き出します。設定をしなくても自動マッピングで出力されます。
“WriteRecord” メソッドにクラスを渡せば、それをルールにのっとり書き出してくれます。
// 参照を追加 => using CsvHelper;
using (var streamWriter = new StreamWriter("people.csv"))
using (var csv = new CsvWriter(streamWriter))
{
// 適当なクラスを渡せば、それっぽく書き出してくれる
csv.WriteRecord(new { a = 1, b = "b1" });
csv.WriteRecord(new { a = 2, b = "b2" });
}
people.csv
1,b1
2,b2
マッピング
Personクラスを定義し、このクラスをマッピングするクラスを使って、CSVを生成します。
Personクラス
public class Person
{
public string Name { get; set; }
public string Kana { get; set; }
public DateTime BirthDate { get; set; }
}
PersonMapperクラス
public class PersonMapper : CsvClassMap<Person>
{
public PersonMapper()
{
Map(x => x.Name).Index(0).Name("氏名");
Map(x => x.BirthDate).Index(1).Name("生年月日").TypeConverterOption("yyyy/MM/dd");
Map(x => x.Kana).Ignore();
}
}
Personクラスはプロパティを定義しただけのクラスです。これをCSVにマッピングするためのルールを定義するのが、PersonMapperクラスです。CsvClassMapクラスを継承し、コンストラクタでマップ情報を定義します。
書き方は例の通りです。Mapメソッドに、ラムダ式で出力するプロパティを指定し、続けて出力の設定を行います。Indexでプロパティを出力する列番号が指定できます。同じようにNameでそのプロパティを出力する列の列名を指定できます。Ignoreを使えば、出力しないという指定もできます。
出力するデータはフォーマットの指定も可能です。
フォーマット
TypeConvertOptionを使えば、データのフォーマットも可能です。以下のコードは公式ドキュメントの引用ですが、数値や日付などのフォーマットをいろいろと指定できます。
public sealed class MyClassMap : CsvClassMap<MyClass>
{
public MyClassMap()
{
Map( m => m.Description ).Index( 0 ).TypeConverterOption( CultureInfo.InvariantCulture );
Map( m => m.TimeStamp ).Index( 1 ).TypeConverterOption( DateTimeStyles.AdjustToUniversal );
Map( m => m.Cost ).Index( 2 ).TypeConverterOption( NumberStyles.Currency );
Map( m => m.CurrencyFormat ).Index( 3 ).TypeConverterOption( "C" );
Map( m => m.BooleanValue ).Index( 4 ).TypeConverterOption( true, "sure" ).TypeConverterOption( false, "nope" );
}
}
サンプル
using CsvHelper;
using CsvHelper.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
public class Program
{
public static void Main(string[] args)
{
var people = new List<Person>();
people.Add(new Person() { Name = "太郎", Kana = "タロウ", BirthDate = new DateTime(1980, 1, 1)});
people.Add(new Person() { Name = "次郎", Kana = "ジロウ", BirthDate = new DateTime(1990, 2, 2)});
people.Add(new Person() { Name = "三郎", Kana = "サブロウ", BirthDate = new DateTime(2000, 3, 3)});
using(var streamWriter = new StreamWriter(@"people.csv"))
using (var csvWriter = new CsvWriter(streamWriter))
{
csvWriter.Configuration.HasHeaderRecord = true;
csvWriter.Configuration.RegisterClassMap<PersonMapper>();
csvWriter.WriteRecords(people);
}
}
public class Person
{
public string Name { get; set; }
public string Kana { get; set; }
public DateTime BirthDate { get; set; }
}
public class PersonMapper : CsvClassMap<Person>
{
public PersonMapper()
{
Map(x => x.Name).Index(0).Name("氏名");
Map(x => x.BirthDate).Index(1).Name("生年月日").TypeConverterOption("yyyy/MM/dd");
Map(x => x.Kana).Ignore();
}
}
}
CsvWriter.Configuration が 出力時の設定情報を管理しています。プロパティでいろいろと設定ができるので眺めてみるとはかどります。CsvWriter.Configuration.RegisterClassMapでマッピングに使うクラスを指定するとその内容でマッピングしてくれます。
上記サンプルコードでは、次のようなCSVが出力されます。指定した列名、列順、フォーマットで内容が出力されていることを確認できます。
氏名,生年月日
太郎,1980/01/01
次郎,1990/02/02
三郎,2000/03/03
まとめ
紹介していませんが、Configurationクラスのプロパティで様々な設定が可能です。ドキュメントやクラス定義を確認して使いこなせればかなり便利なライブラリです。
次回は、読み込みをまとめます。
コメントを書く