こんにちは、トミセン(@tomisenblog)です。
プログラミングやると必ずといっていいほど、使うことになるCSVファイルだけど
「C#でCSVファイルを読み込むにはどうしたらいいの?」
「CSVファイルを読み込めたけど、いまいちやりたいとおりにならない…」
ってこと、けっこう多いですよね。
ネットに載っている情報も新しいものも古いものもあって、何を選べばいいのか分からないし。
それに、サンプルをそのまま使ってみても、うまく動かなくてやり直しなんてことも多いです。
今回はそんなお悩みを解決していきます。
今日は、すごく簡単なCSVファイルの読み込む方法について紹介します。
現場レベルのCsvHelperの実装サンプルを作りました。
CSVデータの取得から、入力チェック、モデル変換まで網羅しています。
5つのシステムで実証したコピペで使い回せる実装法
» 【CsvHelper マスター講座】を見る
C#でCSVファイルを読み込む方法は?
1番オススメの方法は『CsvHelper』
Microsoft製の”TextFieldParser”というライブラリもありますが、CsvHelperというオープンソースのライブラリを使用する方法がオススメです。
ソースはGitHubで管理されているので、リンクから見ることができます。
ライブラリだけでいいなら、Visual StudioのNuGetパッケージの管理からインストールできます。
次で、なぜオススメするのか理由を紹介していきます。
どうして『CsvHelper』なの?優れている点は?
CsvHelperはCSVの読み込みに特化したライブラリです。とても多くの機能をもっています。
1番のポイントは、CSVデータのクラスへのマッピングです。どの列をどのプロパティにセットするかが簡単に管理できます。
それ以外にもプロパティの設定だけでいろいろな問題に対応できます。最低限のコードだけで、難しいコードを書く必要がありません。
次で、もう少し具体的に見ていきましょう。
『CsvHelper』使うと、どんなことができるの?
先ほど少しお話しましたが、CsvHelperはプロパティの設定だけでいろいろなことができます。
ここで全て解説はしませんが、興味がある方はCsvHelperのConfigurationについて書いた記事をぜひご覧ください。Configurationの設定自体の解説はもちろん、例外についても紹介しています。
できること①:ヘッダのあり・なしの変更
最初の行からデータが入力されているCSVもあれば、最初の行がヘッダ(項目の名称)のCSVファイルもありますよね。
ヘッダあり
名前,住所
鈴木,東京都
佐藤,千葉県
ヘッダなし
鈴木,東京都
佐藤,千葉県
どちらのCSVもConfiguration.HasHeaderRecordの設定で読み込みができます。
できること②:区切り文字の変更
CSVはComma Separated Valueの意味で、『,』(カンマ)でフィールドが区切られているファイルのことです。ですが区切り文字が必ずカンマとは限りません。スペースやセミコロンのものもあります。
Configuration.Delimiterで設定が変えられます。デフォルトは「カンマ」です。
できること③:空行の無視
CSVファイルに空白行がないとは限りません。読み取り時には空白行を無視したい場合がほとんどだと思います。
Configuration.IgnoreBlankLinesで無視するかどうか設定できます。デフォルトは「空白行を無視する」です。
できること④:CSVの列フィールドの増減チェック
誤ってデータを編集してしまうと、列フィールドを消してしまったり、逆に増やしてしまったりということがあります。そんなときは前後のデータ行と比較して、列数の変化を検出することができます。
Configuration.DetectColumnCountChangesで列数の変化を検出して例外として扱うか設定できます。
CsvHelperでCSVファイルを読み込んでみよう
ここからはC#でCSVを読み込むための具体的な方法について紹介します。
サンプルコードを使って解説していきますので、一緒に見ていきましょう。
検証したCsvHelperは、バージョン 15.0.0です。
テストデータ
空白行(2行目)が含まれているデータです。
鈴木,東京都
佐藤,千葉県
ソースコード
public class Test
{
public void Main()
{
List<Member> members = null;
using (var reader = new StreamReader(@"C:csvtest.csv", Encoding.GetEncoding("SHIFT_JIS")))
using (var csv = new CsvHelper.CsvReader(reader, new CultureInfo("ja-JP", false)))
{
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.Delimiter = ",";
csv.Configuration.IgnoreBlankLines = true;
members = csv.GetRecords<Member>().ToList();
}
foreach (var member in members)
{
Console.WriteLine($"Name:{member.Name} Address:{member.Address}");
}
}
}
/// <summary>
/// データ格納用クラス
/// </summary>
public class Member
{
[Index(0)]
public string Name { get; set; }
[Index(1)]
public string Address { get; set; }
}
// 【実行結果】
// Name:鈴木 Address:東京都
// Name:佐藤 Address:千葉県
ソースコードだけでは分かりにくい部分があるので、いくつかのポイントをコードを見ながら解説していきます!
CsvHelperを利用するためには、まず開くファイル、エンコードを指定してStreamReaderを生成しなければなりません。
それを指示しているのが次の場所になります。
// ファイルパスの指定、文字コードを『SHIFT_JIS』に指定
using (var reader = new StreamReader(@"C:csvtest.csv", Encoding.GetEncoding("SHIFT_JIS")))
ここでは、CSVファイルパスとエンコーディングを指定してファイルを開きます。
今回はSHIFT_JISですが、必要に合わせてUTF-8などに変えてください。
ファイルを開くことができたら、次はCsvHelperを使う用意をします。
// カルチャを『日本語 - 日本』に指定
using (var csv = new CsvHelper.CsvReader(reader, new CultureInfo("ja-JP", false)))
先程のStreamReaderとカルチャを指定して、CsvHelper.CsvReaderを準備します。
あとはプロパティを利用して、CSVファイルを思い通りに読み込めるように設定していきます。
csv.Configuration.HasHeaderRecord = false; // ヘッダーなし
csv.Configuration.Delimiter = ","; // 区切り文字『,』
csv.Configuration.IgnoreBlankLines = true; // 空白行を無視する
例ではベッダー、区切り文字、空白行の設定をしています。他にも設定したいものがあればここで指定していきます。
設定が終われば、早速CSVファイルを読み込んでいきましょう。
ファイルの最終行まで一行ずつ読み込むようなループは必要ありません。全行読み込むためのメソッドが用意されているので、それを利用します。
// CSVデータの列フィールド → クラスのプロパティにセット
return csv.GetRecords<Member>().ToList();
GetRecordsはCSVファイルの全行を読み込んで<Member>
で指定されたクラスにマッピングして返します。
最後に非常に大切なポイントです!
CSVデータの列フィールドとクラスのマッピングの指定が必要です。クラスにコードを追加します。
[Index(0)] // ← CSVデータの列フィールドのインデックスを指定してマッピングする
public string Name { get; set; }
[Index(1)] // ← CSVデータの列フィールドのインデックスを指定してマッピングする
public string Address { get; set; }
[Index(0)]の”0”の部分をCSVデータの列フィールドのインデックスと一致させます。
これだけでCSVとクラスとのマッピングができます。
これでCSVを読み込むことができました!
まとめ
CsvHelperは、使いこなせればとても便利です。
いろいろと書かなければいけない難しいコードが、Configurationクラスのプロパティの設定で解決してしまいます。
もっとCsvHelperを使いこなしたい方は、Genericsを使って変換するクラスの汎用化から挑戦してみてください。汎用化の方法は「CsvHelper CsvClassMapを使わない方法」をぜひご覧ください。
例外処理やデータ型を変換してのマッピングについては、時間を見つけて記事を書きたいと思います。
それでは、また。
こちらの記事も読まれています!