在.NET项目开发过程中,CSV文件作为轻量通用的数据存储格式,经常被用于数据导入导出、日志记录等场景。手动解析CSV文件需要处理分隔符识别、引号转义、编码转换等复杂逻辑,不仅开发效率低还容易出错。CsvHelper是一款专为.NET平台设计的CSV处理库,支持灵活的读写配置和自定义映射,能很好地解决这些痛点。

CsvHelper的安装方式
可以通过NuGet包管理器快速安装CsvHelper,支持.NET Framework和.NET Core等所有主流.NET版本。在Visual Studio的包管理器控制台执行以下命令即可完成安装:
Install-Package CsvHelper
也可以在项目文件里直接添加包引用,之后执行还原操作即可:
<PackageReference Include="CsvHelper" Version="30.0.1" />
基础CSV读取操作
首先定义一个和CSV列对应的实体类,方便后续映射数据:
public class UserInfo
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
假设当前目录下有一个名为user.csv的文件,内容如下:
Id,Name,Age,Email 1,张三,25,zhangsan@ipipp.com 2,李四,28,lisi@ipipp.com 3,王五,22,wangwu@ipipp.com
使用CsvHelper读取该文件并转换为实体列表的代码如下:
using System.Globalization;
using CsvHelper;
using System.IO;
// 打开文件流
using var reader = new StreamReader("user.csv");
// 创建CsvReader实例,指定文化信息为不变文化,避免不同地区数字格式冲突
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
// 读取所有记录到实体列表
var userList = csv.GetRecords<UserInfo>().ToList();
foreach (var user in userList)
{
Console.WriteLine($"ID:{user.Id},姓名:{user.Name},年龄:{user.Age},邮箱:{user.Email}");
}
基础CSV写入操作
将实体列表写入CSV文件的实现逻辑如下:
using System.Globalization;
using CsvHelper;
using System.IO;
// 准备要写入的数据
var writeList = new List<UserInfo>
{
new UserInfo { Id = 4, Name = "赵六", Age = 30, Email = "zhaoliu@ipipp.com" },
new UserInfo { Id = 5, Name = "孙七", Age = 26, Email = "sunqi@ipipp.com" }
};
// 创建写入流
using var writer = new StreamWriter("new_user.csv");
// 创建CsvWriter实例
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
// 写入记录,会自动生成表头
csv.WriteRecords(writeList);
自定义映射规则
当CSV列名和实体属性名不一致时,可以通过ClassMap自定义映射关系。比如CSV里的列名是user_id,对应实体的Id属性,配置方式如下:
using CsvHelper.Configuration;
public class UserInfoMap : ClassMap<UserInfo>
{
public UserInfoMap()
{
// 映射CSV的user_id列到Id属性
Map(m => m.Id).Name("user_id");
// 映射CSV的user_name列到Name属性
Map(m => m.Name).Name("user_name");
// 映射CSV的user_age列到Age属性
Map(m => m.Age).Name("user_age");
// 映射CSV的user_email列到Email属性
Map(m => m.Email).Name("user_email");
}
}
使用自定义映射时,需要在读取或写入前注册映射配置:
using System.Globalization;
using CsvHelper;
using System.IO;
using var reader = new StreamReader("custom_user.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
// 注册自定义映射
csv.Context.RegisterClassMap<UserInfoMap>();
var userList = csv.GetRecords<UserInfo>().ToList();
常见配置与异常处理
CsvHelper提供了丰富的配置项,比如忽略表头、设置分隔符、处理空值等。以下是几个常用配置示例:
using System.Globalization;
using CsvHelper;
using CsvHelper.Configuration;
using System.IO;
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
// 忽略CSV文件的表头,直接读取数据行
HasHeaderRecord = false,
// 设置自定义分隔符,默认是逗号
Delimiter = "|",
// 遇到空值时不抛出异常
IgnoreBlankLines = true,
// 自动检测字段分隔符
DetectDelimiter = true
};
using var reader = new StreamReader("custom_delimiter.csv");
using var csv = new CsvReader(reader, config);
var userList = csv.GetRecords<UserInfo>().ToList();
读取过程中如果出现列数不匹配、类型转换失败等问题,CsvHelper会抛出对应的异常,可以通过try-catch块捕获并处理:
using System.Globalization;
using CsvHelper;
using CsvHelper.Exceptions;
using System.IO;
try
{
using var reader = new StreamReader("error_user.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
var userList = csv.GetRecords<UserInfo>().ToList();
}
catch (ReaderException ex)
{
Console.WriteLine($"读取CSV文件失败:{ex.Message}");
}
catch (ValidationException ex)
{
Console.WriteLine($"数据验证失败:{ex.Message}");
}
常用场景扩展
如果需要处理没有固定表头、动态列的CSV文件,可以不使用强类型实体,直接读取为动态对象或者字典:
using System.Globalization;
using CsvHelper;
using System.IO;
using var reader = new StreamReader("dynamic.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
// 读取为字典集合,键是列名,值是对应单元格内容
var records = csv.GetRecords<dynamic>().ToList();
foreach (var record in records)
{
// 动态访问列内容
Console.WriteLine(record.Name);
}