前言:介绍下一款读写操作csv文件的.NET库,可以实现将csv中数据读到自定义类集合中。
CsvHelper版本:28.0.1
一、简介
一款适用于c#的对csv文件进行读写的.NET库,目前最新更新的支持.NET6。Github 地址:GitHub - JoshClose/CsvHelper: Library to help reading and writing CSV files

二、主要API
2.1 CsvHelper
读写CSV文件数据的核心类,包括但不限于读写等操作。

2.2 CsvHelper.Configuration
配置 CsvHelper 读写行为的类,这里面包含了一些配置信息的内容,包括映射自定义类等。

2.3 CsvHelper.Configuration.Attributes
配置 CsvHelper 的特性。可以对需要映射的自定义类进行一些设置。

2.4 CsvHelper.Expressions
生成 LINQ 表达式的类,类似于sql语句,方便检索。

2.5 CsvHelper.TypeConversion
这里面主要包括了将 CSV 字段与 .NET 类型相互转换的类。

三、简单使用
3.1 特性
没有提供映射文件的情况下,默认为自动映射,自动映射会按顺序依次映射到类的属性中去。如果属性是一个自定义类,那么会继续一次按照这个自定义的属性进行填写。如果出现循环引用,那么自动映射会停止。
需求:将csv文件中的数据提取到自定义类中, csv文件中的列名(如果有)需要和类的属性名相同。
这里csv中没有列名,下面操作也是针对没有列名的情况下。

没有列名情况下,需要对自定义类的属性进行设置,使用 Attributes(特性)进行设置。
Index:用于标记字段顺序,在读取文件时,如果没有标题,就只能通过顺序来确定字段。
- public class CsvModel
- {
- [Index(0)]
- public DateTime Dt { get; set; }
- [Index(1)]
- public string Value1 { get; set; }
- [Index(2)]
- public string Value2 { get; set; }
- [Index(3)]
- public string Value3 { get; set; }
- [Index(4)]
- public string Value4 { get; set; }
- [Index(5)]
- public string Value5 { get; set; }
- [Index(6)]
- public string Value6 { get; set; }
- [Index(7)]
- public string Value7 { get; set; }
- [Index(8)]
- public string Value8 { get; set; }
- [Index(9)]
- public string Value9 { get; set; }
- [Index(10)]
- public string Value10 { get; set; }
- [Index(11)]
- public string Value11 { get; set; }
- [Index(12)]
- public string Value12 { get; set; }
- }
- using (var reader = new StreamReader("路径.csv"))
- {
- using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
- {
- var records = csv.GetRecords<类>();
- }
- }

原csv文件中的第一行数据被舍弃掉,这里是因为HasHeaderRecord默认是true,就是将第一行作为标题,但又同时设置了Index属性,因此就自动屏蔽第一行数据了。这是个人猜想,供各位批斗。

这样设置下CsvConfiguration就正常了。

其实这个 问题在早期版本中是可以通过下面这一行代码来设置,早期版本这个属性还是有set的,后来变成只有get的只读模式了,设置是否将第一行作为标题也改为了上面的模式。
csv.Configuration.HasHeaderRecord = true;//是否将第一行作为标题
3.2 映射
这种方式的需求是因为csv文件列名和类字段名称不相同,而且没法给要映射的类添加特性,可以使用ClassMap方式手动进行映射。通过定义一个映射匹配类,这样CsvHelper就会自动根据你的类来自动映射匹配。使用映射和使用特性达到的效果是一样的。
- using (var reader = new StreamReader(csv文件路径))
- using (var csv = new CsvReader(reader, config))
- {
- csv.Context.RegisterClassMap
(); -
- var records = csv.GetRecords
(); //一次性读取所有数据,并且转换为对象集合。 - }
-
- //自定义类
- public class CsvModel
- {
-
- public DateTime Dt { get; set; }
-
- public string Value1 { get; set; }
-
- public string Value2 { get; set; }
-
- public string Value3 { get; set; }
-
- public string Value4 { get; set; }
-
- public string Value5 { get; set; }
-
- public string Value6 { get; set; }
-
- public string Value7 { get; set; }
-
- public string Value8 { get; set; }
-
- public string Value9 { get; set; }
-
- public string Value10 { get; set; }
-
- public string Value11 { get; set; }
-
- public string Value12 { get; set; }
-
- }
-
- //映射类
- public class CsvModelMap:ClassMap<CsvModel>
- {
- CsvModelMap()
- {
- Map(m=>m.Dt).Name("Dt");//使用文件列名称指定映射
- Map(m => m.Value1).Name("Value1");
- Map(m => m.Value2).Name("Value2");
- Map(m => m.Value3).Name("Value3");
- Map(m => m.Value4).Name("Value4");
- Map(m => m.Value5).Name("Value5");
- Map(m => m.Value6).Name("Value6");
- Map(m => m.Value7).Name("Value7");
- Map(m => m.Value8).Name("Value8");
- Map(m => m.Value9).Name("Value9");
- Map(m => m.Value10).Name("Value10");
- Map(m => m.Value11).Name("Value11");
- Map(m => m.Value12).Name("Value12");
- }
- }

同样的,这个配置函数经过迭代后发生了变化, 原来配置方式是下面这样的。
csv.Configuration.RegisterClassMap();
四、参考文献