CSV ファイルって何よ
rfc 4180 で定義されているファイル形式の事。CSV とは Comma Separated Values の頭文字をとったもの。 www.rfc-editor.org
ざっくりとファイルの中身は以下のように定義されてる。
- 各レコードは CRLF によって区切られた個別の行に配置される。
- 末尾のレコードは CRLF を含まなくても良い。
- ヘッダー行を含める事が出来る。
- 各レコードのフィールドは「,」で区切られる。末尾のフィールドは「,」を持っちゃはダメ。
- 各フィールドは「"」で囲んでも良い。囲まない場合、フィールドに「"」を含めちゃダメ。
- フィールドに「"」「CRLF」「,」を含める場合は、フィールドを「"」で囲まないといけない
- フィールドに「"」を含める場合、「"」で囲った上で別の「"」を使ってエスケープしないといけない。
7 が分かりにくいので例を残しておく。
"aaa""bb" // これは OK。aaa"bb というフィールドになる。 "aaa"bb" // これは NG。" の前にエスケープ用の " を置かないといけない。
といった定義が CSV ファイルにはある。 この定義を守ってファイルを取り扱うのは少々面倒なので CsvHelper っていうライブラリを使う。
CsvHelper
OSS です。
C# で定義した class を CSV のヘッダーとしてマップしたり、また CSV のフィールドを class にマップしたり出来ます。
また、RFC 4180 に準拠しているので、特に意識することなく 1 で紹介した形式を守ってくれます。システム間の互換性とか保ってくれますね。
RFC 4180 に準拠させたくない時は CsvMode を使う。CsvWriter
とか CsvReader
をインスタン化させる時に new CsvConfiguration
に RFC4180 以外の CsvMode
を渡す。
デフォは RFC4180 。
使い方は簡単で、Package Manger Console、もしくは .NET CLI Console で以下のコマンドを叩くだけ。
// Package Manager Console PM> Install-Package CsvHelper // .NET CLI Console > dotnet add package CsvHelper
repository はこちらGitHub - JoshClose/CsvHelper: Library to help reading and writing CSV files
Document はこちらA .NET library for reading and writing CSV files. Extremely fast, flexible, and easy to use. | CsvHelper
CSV ファイルを一行ずつ読み込む
使い方は超絶簡単。
まずは一番シンプルな使い方の、一行ずつ読み込んでいくスタイル。
internal class CsvReadExample { // Replace with the directory path where the csv is saved private const string Path = @""; public void ReadCsv() { using var reader = new StreamReader($@"{Path}\user.csv"); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); while(csv.Read()) { var user = csv.GetRecord<UserRecord>(); Console.WriteLine($"Id: {user.Id}, Name: {user.Name}, Email: {user.Email}"); } } } internal record UserRecord(int Id, string Name, string Email);
複数行をまとめて読み込む
public void ReadMultiRecords() { using var reader = new StreamReader($@"{DirectoryPath}\user.csv"); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); //var users = csv.GetRecords<UserRecord>().ToList(); var users = csv.GetRecords<UserRecord>(); foreach(var user in users) Console.WriteLine($"Id: {user.Id}, Name: {user.Name}, Email: {user.Email}"); }
CsvReader に GetRecords ってメソッドが用意されてあるからこれを使う。内部的には一行ずつ読み取ってるから上の例とやってる事は同じだけど、呼び出し側がシンプルになるから良いね。
yield return
で一行ずつ末尾まで読み取るような実装になってるから、戻り値を ToList()
とかしちゃうとメモリをバカ食いしてしまう。メモリに置きたい時は丁寧に実装する。
また時間があれば続きを書く。Attribute も試してみたい。