【Fire HD 10 第13世代用】保護フィルム ガラスタイプ 光沢 ブルーライトカット 気泡レス加工 1枚入り
¥2,480 (2025年4月25日 13:08 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)【1m+1m+2m 3本/黒】RAMPOW usb c ケーブル タイプc ケーブル QC3.0対応高速充電 データ転送USB2.0規格 iPhone 16/16e 充電ケーブル/iPhone 15 充電ケーブル Sony Xperia/Samsung/Asus Zenfone/Fujitsu Arrows/PS5コントローラー タイプc多機種対応 在宅勤務支援
¥999 (2025年4月25日 13:07 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)
Csv-CSharpという、CSVの解析やシリアライズ/デシリアライズを行うためのライブラリを公開しました!かなり前からプレビュー版として公開はしていましたが、ある程度安定してきたので正式リリースとすることにしました。
既にC#にはCsvHelperやSep等のライブラリがありますが、Csv-CSharpの最大の特徴はシリアライザとしてのAPIを整えてあることでしょう。
var array = new Person[]
{
new() { Name = "Alice", Age = 18 },
new() { Name = "Bob", Age = 23 },
new() { Name = "Carol", Age = 31 },
}
string csv = CsvSerializer.SerializeToString(array);
array = CsvSerializer.DeserializePerson>(csv);
[CsvObject]
public partial class Person
{
[Column(0)]
public string Name { get; set; }
[Column(1)]
public int Age { get; set; }
}
System.Text.JsonやMessagePack-CSharpに近いAPIでCSVと配列を相互に変換することが可能です。もちろん対応する型を定義することなく、直接CSVの構造を解析する機能も提供されています。
また、高いパフォーマンスも特徴の一つです。Source Generatorを活用した設計により、非常に高いパフォーマンスを発揮するようになっています。CsvHelperやServiceStack.Textはもちろん、現状最速を掲げているSepともほぼ同等、Csv-CSharpに有利な状況であればより高速な解析が可能です。
Sepは良好なパフォーマンスの反面、APIにやや癖があったり、最新の.NETの機能に頼っているためUnityでは使えないなどの問題がありました。Csv-CSharpは.NET標準に沿った自然なAPIで構成されているほか、.NET Standard 2.1にも対応しているためUnityでも利用可能です。
さらに、Csv-CSharpはIBufferWriter
/ReadOnlySequence
のようなモダンなI/O APIにも対応しています。これによりバッファ管理を外部に任せられる場合は更なる性能の向上が見込めます。
使い方
既に冒頭でも紹介した通り、CSVをデータの配列とみてSerialize()
/Deserialize()
するのが基本の使い方となります。最大のパフォーマンスを発揮したい場合はstringを通さずにUTF-8ベースのAPIを利用します。
byte[] csv = CsvSerializer.Serialize(array);
array = CsvSerializer.DeserializePerson>(csv);
また、対象の型にはpartial
キーワードと[CsvObject]
属性、メンバーが対応する[Column]
属性が必須です。また、シリアライズの際に無視したいメンバーには[IgnoreMember]
属性を追加してください。これが足りない場合はAnalyzerがコンパイルエラーを出力します。
[CsvObject]
public partial class Person
{
[Column(0)]
public string Name { get; set; }
[Column(1)]
int age;
[IgnoreMember]
public int Age => age;
}
[Column]
の引数はint
またはstring
が利用できます。int
の場合は対象の列数が、string
の場合は同名のCSVのヘッダーが対応します。
また、プロパティ名をそのまま[Column]
の引数として利用したい場合は[CsvObejct(keyAsPropertyName: true))]
を指定することが可能です。
[CsvObject(keyAsPropertyName: true)]
public partial class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
この辺りの仕様はMessagePack-CSharpと全く同じになるようになっています。MessagePack-CSharpのAPIは本当に良く出来ているので…
CsvDocument
とはいえ、わざわざ対象の型を作るまでもないデータであったり、そもそもデータにキッチリ対応する型を作ることができないケースもあるでしょう。その場合はCsvDocument
で直接解析することが可能です。
var document = CsvSerializer.ConvertToDocument(csv);
foreach (var row in document.Rows)
{
var name = row["Name"].GetValuestring>();
var age = row["Age"].GetValueint>();
}
こちらも直感的で扱いやすいAPIになっているのではないでしょうか。通常のSerialize()
/Deserialize()
より若干パフォーマンスは落ちますが、それでも十分高速です。
カスタマイズ
シリアライズの際にCsvOptions
を渡すことで動作をカスタマイズすることが可能です。
CsvSerializer.Serialize(array, new CsvOptions()
{
HasHeader = true,
AllowComments = true,
NewLine = NewLineType.LF,
Separator = SeparatorType.Comma,
QuoteMode = QuoteMode.Minimal,
FormatterProvider = StandardFormatterProvider.Instance,
});
これにより#
によるコメントを許可したり、Separator
を変更することでTSVなどの解析を行ったりなども可能になっています。
また、CSVの各要素のパースについてはICsvFormatter
とICsvFormatterProvider
を差し替えることでカスタマイズできます。例として、int
をラップする構造体のFormatterを作成してみましょう。
public struct Foo
{
public int Value;
public Foo(int value)
{
this.Value = value;
}
}
public sealed class FooFormatter : ICsvFormatterFoo>
{
public Foo Deserialize(ref CsvReader reader)
{
var value = reader.ReadInt32();
return new Foo(value);
}
public void Serialize(ref CsvWriter writer, Foo value)
{
writer.WriteInt32(value.Value);
}
}
このFormatterを利用するには、対応するFormatterProvider
をセットで作成します。この例ではFormatterが1つだけですが、複数ある場合も単一のFormatterProviderにまとめることが可能です。
public class CustomFormatterProvider : ICsvFormatterProvider
{
public static readonly ICsvFormatterProvider Instance = new CustomFormatterProvider();
CustomFormatterProvider()
{
}
static CustomFormatterProvider()
{
FormatterCacheFoo>.Formatter = new FooFormatter();
}
public ICsvFormatterT>? GetFormatterT>()
{
return FormatterCacheT>.Formatter;
}
static class FormatterCacheT>
{
public static readonly ICsvFormatterT> Formatter;
}
}
あとはこれをCsvOptions
に渡してやればOKです。
var provider = CompositeFormatterProvider.Create(
CustomFormatterProvider.Instance,
StandardFormatterProvider.Instance
);
CsvSerializer.Serialize(array, new CsvOptions()
{
FormatterProvider = provider
});
要するにMessagePack-CSharpのFormatter / Resolverですね。これもそのまんまです。
パフォーマンスのために柔軟性を若干犠牲にしてる部分はあるので、CsvHelperと比較すると若干カスタマイズの余地は少ないかもしれません。ただ、ほとんどのユースケースでは十分と言えるだけの機能は備わっているでしょう。
CSVの仕様
実はCSVも明文化された仕様は定められていて、RFC-4180で確認することができます。しかし、現実にはこの仕様に沿っていないCSVの方が多いでしょう。というかCsv-CSharpのデフォルトも厳密にはこの仕様に沿っていないですし。
というわけでCsv-CSharpではこの仕様から外れたCSVもある程度許容して解析できるようになっています。.csvとは名ばかりの魔改造CSVデータが投げられたらどうしようもないですが、まあそれはしょうがないということで…
まとめ
CSVの解析は比較的簡単にできるので、自前で実装している人も多いでしょう。ただ、どうしても自前でやっていると実装ミスが生じたり、データの変更に柔軟に対応できなかったりします。
また、C#の文字列周り、特にUTF-8の最適化は結構複雑で、都度適切に実装するのはかなり大変です。そのため、こういったガチガチに最適化された、それでいて手軽に扱えるライブラリを提供しておくことは重要でしょう。
というわけで、CSVを扱う際には是非使ってみてください〜!