「CsvHelperって、けっこう使われている割に情報が少ない・・・。」
「CsvHelperって、やりたいこと調べるのに時間がかかる・・・。」
こんなことを悩んでいませんか?
こういった疑問に答えます。
今日は「CsvHelper.BadDataFound」について紹介します。
現場レベルのCsvHelperの実装サンプルを作りました。
CSVデータの取得から、入力チェック、モデル変換まで網羅しています。
5つのシステムで実証したコピペで使い回せる実装法
» 【CsvHelper マスター講座】を見る
CsvHelper BadDataFoundとは?
どんな設定?
フィールドに引用符が含まれているなど、不正なデータが含まれている場合に利用する設定です。
ConfigurationのBadDataFoundを使うとCsvHelper.BadDataExceptionをスローする代わりに、実行する独自の関数を設定できます。
ソースコード例①
検証したCsvHelperは、バージョン 15.0.0です。
テストデータ
“Jo”hn”が不正なデータが含まれているフィールドです。
"Jo"hn","Doe",43
"Jane","Doe",21
ソース
public class Test
{
public void Main()
{
var csvFormats = CsvHelperPerformer.GetRecords<CsvModel>(@"C:csvtest.csv");
}
}
public class CsvHelperPerformer
{
/// <summary>
/// ファイルを読み込む
/// </summary>
/// <typeparam name="T">変換するクラス</typeparam>
/// <param name="path">ファイル</param>
public static List<T> GetRecords<T>(string path)
{
using (var reader = new StreamReader(path, Encoding.GetEncoding("SHIFT_JIS")))
using (var csv = new CsvReader(reader, new CultureInfo("ja-JP", false)))
{
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.BadDataFound = x =>
{
Console.WriteLine($"Bad data: <{x.RawRecord}>"); // 不正なデータが含まれている場合の処理を書く。メソッド化してもOK
};
return csv.GetRecords<T>().ToList();
}
}
}
public class CsvModel
{
[Index(0)]
public string FirstName { get; set; }
[Index(1)]
public string LastName { get; set; }
[Index(2)]
public int Age { get; set; }
}
// 【実行結果】
// Bad data: <"Jo"hn",>
このように不正なデータが含まれているフィールドを見つけたら、独自の関数を実行させます。
x.RawRecordで出力されるデータは、行全体のデータではなく、フィールドのデータです。
ソースコード例②
ConfigurationのBadDataFoundを設定しない場合の例です。
テストデータ
先ほどのと同じデータです。
ソース
public class Test
{
public void Main()
{
try
{
var csvFormats = CsvHelperPerformer.GetRecords<CsvModel>(@"C:csvtest.csv");
}
catch (CsvHelper.BadDataException ex)
{
Console.WriteLine($"エラー:{ex.ReadingContext.Row}行目のデータのフィールドに引用符が含まれています。");
Console.WriteLine($"値:{ex.ReadingContext.RawRecord}");
}
}
}
public class CsvHelperPerformer
{
/// <summary>
/// ファイルを読み込む
/// </summary>
/// <typeparam name="T">変換するクラス</typeparam>
/// <param name="path">ファイル</param>
public static List<T> GetRecords<T>(string path)
{
using (var reader = new StreamReader(path, Encoding.GetEncoding("SHIFT_JIS")))
using (var csv = new CsvReader(reader, new CultureInfo("ja-JP", false)))
{
csv.Configuration.HasHeaderRecord = false;
return csv.GetRecords<T>().ToList();
}
}
}
public class CsvModel
{
[Index(0)]
public string FirstName { get; set; }
[Index(1)]
public string LastName { get; set; }
[Index(2)]
public int Age { get; set; }
}
// 【実行結果】
// 例外がスローされました: 'CsvHelper.BadDataException' (CsvHelper.dll の中)
// エラー:1行目のデータのフィールドに引用符が含まれています。
// 値:"Jo"hn",
CsvHelper.BadDataExceptionの例外がスローされます。
CsvHelper.BadDataExceptionは、ConfigurationにDetectColumnCountChanges = trueが設定されていた場合(デフォルトはfalse)には、列数の変化を検知して例外をスローするので例外処理の切り分けが必要になります。
ポイントBadDataFound設定しない場合、CsvHelper.BadDataExceptionがスローされます。
CsvHelper.BadDataExceptionについて知りたい方は「CsvHelper BadDataExceptionとは?」の記事で書いているので、そちらを見てください。

まとめ
CsvHelperのConfigurationの設定や例外処理って、難しいですよね。でも使いこなせれば便利だなぁといつも思っています。
他のConfigurationの設定や例外について知りたい方は「CsvHelper Configurationの設定」の記事でも書いていますのでどうぞ。



