【C#】CsvHelperによるCSVファイルの読み込み・書き込み方法

【C#】CsvHelperによるCSVファイルの読み込み・書き込み方法

CsvHelperによるCSVファイルの読み込み・書き込み方法について記載します。

<確認環境>
Windows10 64bit
Visual Studio 2022
.NET6.0
CsvHelper v30.0.1

CsvHelperとは

CsvHelperはCSVファイルの読み書きを簡単に行えるオープンソースライブラリです。
ライセンスは MS-PL または Apache-2.0 のいずれかで使用できます。商用利用は完全無料です。
https://joshclose.github.io/CsvHelper/

CsvHelperのインストール

Visual Studio のメニューから[ツール] > [NuGet パッケージマネージャー] > [パッケージマネージャーコンソール] を選択して以下のコマンドを実行します。

Install-Package CsvHelper

または、[プロジェクト] > [NuGetパッケージ管理] でCsvHelperを検索してインストールします。
CsvHelperインストール

CsvReaderによるCSVファイルの読み込み

CsvReaderクラスでCSVファイルを読み込みます。以下はGetRecords<T>メソッドを使用してデータ行をIEnumerable<T>で取得します。 ジェネリック型<T>にはデータ保持クラスを指定します。データ保持クラスはCSVデータとマッピングします。

商品名,金額
チョコレート,100
アイスクリーム,200

using CsvHelper;
using CsvHelper.Configuration.Attributes;
using System.Globalization;

// CSVファイルの読み込み
using (var reader = new StreamReader(@".\csv\Product.csv"))
{
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        // CSVデータをデータ格納クラス(Productクラス)で取得
        var products = csv.GetRecords<Product>();

        // products変数の内容
        // Name:チョコレート    Price:100
        // Name:アイスクリーム  Price:200
    }
}

// データ格納クラス
public class Product
{
    [Name("商品名")]
    public string? Name { get; set; }
    [Name("金額")]
    public int Price { get; set; }
}

CsvWriterによるCSVファイルの書き込み

CsvWriterクラスでCSVファイルを書き込みます。以下はヘッダー行、データ行、コメント行を書き込むメソッドを使用しています。

using CsvHelper;
using CsvHelper.Configuration.Attributes;
using System.Globalization;

// CSVファイルの書き込む
using (var writer = new StreamWriter(@".\csv\Product.csv"))
{
    using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
    {
        // ヘッダー行書き込み
        csv.WriteHeader<Product>();
        csv.NextRecord();   // 改行する

        // データ行を1行書き込み
        csv.WriteRecord(new Product() { Name = "チョコレート", Price = 100 });
        csv.NextRecord();  // 改行する

        // コメント行書き込み
        csv.WriteComment("コメント");
        csv.NextRecord();  // 改行する

        // データ行を複数書き込み
        var datas = new List<Product>()
        {
            new Product { Name = "アイスクリーム", Price = 200 },
            new Product { Name = "クッキー", Price = 300 }
        };
        csv.WriteRecords(datas);
    }
}

// データ格納クラス
public class Product
{
    [Name("商品名")]
    public string? Name { get; set; }
    [Name("金額")]
    public int Price { get; set; }
}

CSVの書き込み結果
商品名,金額
チョコレート,100
#コメント
アイスクリーム,200
クッキー,300

CsvConfigurationの設定

CsvConfigurationクラスのプロパティにCSVファイルの読み書きに関連する項目を設定します。CsvConfigurationクラスはCsvReaderメソッドやCsvWriterメソッドに渡すことで使用します。

using CsvHelper;
using CsvHelper.Configuration;

// CsvConfiguration作成
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    // CSVファイルのコメント行を許可
    AllowComments = true,
    // CSVファイルのエンコードをUnicodeに設定
    Encoding = Encoding.Unicode,
    // CSVファイルにヘッダー行なし
    HasHeaderRecord = false
};

// CSVファイル読み込み
using (var reader = new StreamReader(@".\csv\XXX.csv"))
{
    using (var csv = new CsvReader(reader, config))  // CsvReaderにCsvConfiguration設定
    {
        // CSVデータ読み込み
        // ・・・
    }
}

// CSVファイル読み込み
using (var writer = new StreamWriter(@".\csv\YYY.csv"))
{
    using (var csv = new CsvWriter(writer, config))  // CsvWriterにCsvConfiguration設定
    {
        // CSVデータ書き込み
        // ・・・
    }
}

CsvConfigurationクラスのプロパティをいくつか記載します。
プロパティ 設定内容
AllowComments CSVファイルのコメント行を許可するか設定します。既定値は false です。
Comment CSVファイルのコメント行を示す文字を設定します。既定値は '#' です。
Delimiter CSVファイルの区切り文字を設定します。既定値は","です。
DetectDelimiter CSVファイルの区切り文字を自動検出するか設定します。既定値は false です。
DetectDelimiterValues CSVファイルの区切り文字を自動検出するときの候補となる区切り文字の配列を設定します。既定値は"," , ";" , "|" , "\t"です。
DetectColumnCountChanges CSVファイルのデータ行のカラム数が一定でないときに 例外をスローするか設定します。既定値は false です。
Encoding CSVファイルのエンコーディングを設定します。既定値は UTF-8 です。
Escape CSVファイルの引用符文字をデータとして扱うためのエスケープ文字を設定します。既定値は '"' です。
HasHeaderRecord CSVファイルにヘッダー行があるか設定します。既定値は true です。
IgnoreBlankLines CSVファイルの空行を無視するか設定します。既定値は true です。
Quote CSVファイルのデータを囲む引用符文字を設定します。
TrimOptions CSVファイルのデータにある空白をトリムするか設定します。既定値はTrimOptions.None(トリム無効)です。

CSVファイルのデータ格納クラス作成とマッピング

CSVファイルのデータを格納するクラスを作成します。 データ格納クラスのプロパティとCSVデータは、Attributeを設定する、または、ClassMap<TClass>を継承したマッピングクラスを作成することでマッピングします。

Nameによるヘッダー名とプロパティのマッピング

Nameメソッドでヘッダー名とデータ格納クラスのプロパティ名をマッピングします。以下はヘッダー名の「商品名」と「金額」でデータ格納クラスのプロパティとマッピングしています。

商品名,金額
アンパン,100
Attributeの使用例
using CsvHelper.Configuration.Attributes;

// データ格納クラス
public class Product
{
    [Name("商品名")]
    public string? Name { get; set; }
    [Name("金額")]
    public int Price { get; set; }
}

マッピングクラスの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    public string? Name { get; set; }
    public int Price { get; set; }
}

// マッピングクラス
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(m => m.Name).Name("商品名");  // ヘッダー名 "商品名" とマッピング
        Map(m => m.Price).Name("金額");   // ヘッダー名 "金額" とマッピング
    }
}

ヘッダー名が異なる可能性があるときは、複数のヘッダー名も指定できます。以下はヘッダー名が日本語または英語のいずれかの可能性があるときです。

ヘッダー名が日本語のCSV
商品名,金額
アンパン,100
ヘッダー名が英語のCSV
ProductName,Price
アンパン,100
Attributeの使用例
using CsvHelper.Configuration.Attributes;

// データ格納クラス
public class Product
{
    [Name("商品名","ProductName")]
    public string? Name { get; set; }
    [Name("金額", "Price")]
    public int Price { get; set; }
}

マッピングクラスの使用例
public ProductMap()
{
    Map(m => m.Name).Name("商品名", "ProductName");
    Map(m => m.Price).Name("金額", "Price");
}

Indexによるデータ記載順とプロパティのマッピング

Indexメソッドでデータの記載順とデータ格納クラスのプロパティ名をマッピングします。

アンパン,100
Attributeの使用例
using CsvHelper.Configuration.Attributes;

// データ格納クラス
public class Product
{
    [Index(0)]
    public string? Name { get; set; }
    [Index(1)]
    public int Price { get; set; }
}

マッピングクラスの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    public string? Name { get; set; }
    public int Price { get; set; }
}

// マッピングクラス
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(m => m.Name).Index(0);   // 商品名(0番目のデータ)とマッピング
        Map(m => m.Price).Index(1);  // 金額(1番目のデータ)とマッピング
    }
}

TypeConverterによるデータ変換

TypeConverterメソッドを使用してデータを変換してデータ格納クラスのプロパティに設定します。CsvHelper.TypeConversionのConverterを継承するデータ変換クラスの作成が必要です。

商品名,金額,色,予約可否
シューズ,3000,ブラック/ホワイト/ネイビー,1
カバン,6000,ブルー/ホワイト,0

Attributeの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    [Name("商品名")]
    public string? Name { get; set; }
    [Name("金額")]
    public int Price { get; set; }
    [Name("色")]
    [TypeConverter(typeof(ColorConvert))]  // ColorConvertによるデータ変換
    public string[] Color { get; set; }
    [Name("予約可否")]
    [TypeConverter(typeof(RSVConvert))]    // RSVConvertによるデータ変換
    public bool RSV { get; set; }
}

// 色プロパティ用のデータ変換クラス
public class ColorConvert : CsvHelper.TypeConversion.ArrayConverter
{
    public override object ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData)
    {
        // 文字列を'/'で分割して返却
        return text.Split('/').ToArray();
    }
}

// 予約可否用のデータ変換クラス
public class RSVConvert : CsvHelper.TypeConversion.BooleanConverter
{
    public override object ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData)
    {
        // "1"ならtrue、それ以外はfalseを返却
        return text == "1";
    }
}

マッピングクラスの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    public string? Name { get; set; }
    public int Price { get; set; }
    public string[] Color { get; set; }
    public bool RSV { get; set; }
}

// マッピングクラス
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(m => m.Name).Name("商品名");
        Map(m => m.Price).Name("金額");
        // ColorConvertによるデータ変換
        Map(m => m.Color).Name("色").TypeConverter<ColorConvert>();
        // RSVConvertによるデータ変換
        Map(m => m.RSV).Name("予約可否").TypeConverter<RSVConvert>();
    }
}

// 色プロパティ用のデータ変換クラス
public class ColorConvert : CsvHelper.TypeConversion.ArrayConverter
{
    public override object ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData)
    {
        // 文字列を'/'で分割して返却
        return text.Split('/').ToArray();
    }
}

// 予約可否用のデータ変換クラス
public class RSVConvert : CsvHelper.TypeConversion.BooleanConverter
{
    public override object ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData)
    {
        // "1"ならtrue、それ以外はfalseを返却
        return text == "1";
    }
}

Convertによるデータ変換

Convertメソッドでデータを変換してデータ格納クラスのプロパティに設定します。Convertメソッドはマッピングクラスのみ使用できます。

商品名,金額,色,予約可否
シューズ,3000,ブラック/ホワイト/ネイビー,1
カバン,6000,ブルー/ホワイト,0

マッピングクラスの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    public string? Name { get; set; }
    public int Price { get; set; }
    public string[] Color { get; set; }
    public bool RSV { get; set; }
}

// マッピングクラス
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(m => m.Name).Name("商品名");
        Map(m => m.Price).Name("金額");
        // データを配列に変換して設定
        Map(m => m.Color).Convert(row =>
        {
            var text = row.Row.GetField("色");
            return text.Split('/').ToArray();
        });
        // データが"1"ならtrue、それ以外はfalseを設定
        Map(m => m.RSV).Convert(row =>
        {
            var text = row.Row.GetField("予約可否");
            return text == "1";
        });
    }
}

Constantによる定数値の設定

Constantメソッドを使用してデータ格納クラスのプロパティに定数値を設定できます。 以下は金額のプロパティに定数値2000を設定しています。

商品名,金額,
アンパン,100

Attributeの使用例
using CsvHelper.Configuration.Attributes;

// データ格納クラス
public class Product
{
    [Index(0)]
    public string? Name { get; set; }
    [Index(1)]
    [Constant(2000)]    // 金額に定数2000を設定
    public int Price { get; set; }
}

マッピングクラスの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    public string? Name { get; set; }
    public int Price { get; set; }
}

// マッピングクラス
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(m => m.Name).Index(0);
        Map(m => m.Price).Index(1).Constant(2000);  // 金額に定数2000を設定
    }
}

Optionalによるマッピングありなしの変更

データがある場合とない場合があるときは、Optionalによるマッピングありなしを変更できます。以下は個数データありなしのCSVどちらにも対応しています。

個数データなしのCSV
商品名,金額
アンパン,100
個数データありのCSV
商品名,金額,個数
アンパン,100,80

Attributeの使用例
using CsvHelper.Configuration.Attributes;

// データ格納クラス
public class Product
{
    [Name("商品名")]
    public string? Name { get; set; }
    [Name("金額")]
    public int Price { get; set; }
    [Name("個数")]
    [Optional]    // 個数データありなしどちらにも対応可能
    public int Quantity { get; set; }
}

マッピングクラスの使用例
using CsvHelper.Configuration;

// データ格納クラス
public class Product
{
    public string? Name { get; set; }
    public int Price { get; set; }
    public int Quantity { get; set; }
}

// マッピングクラス
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(m => m.Name).Name("商品名");
        Map(m => m.Price).Name("金額");
        Map(m => m.Quantity).Name("個数").Optional();  // 個数データありなしどちらにも対応可能
    }
}


Next Post Previous Post