在 C# (.NET) 中处理 CSV:工具概览与示例
CSV(逗号分隔值)是交换表格数据最常用的格式之一。在 C# (.NET) 生态系统中,有几种可靠的方法来处理这种格式:从内置工具到强大的第三方库。在本文中,我们将介绍主要方法和最佳实践。
为什么不应该手动编写 CSV 解析器?
CSV 格式乍看起来很简单,但在实践中包含许多细微之处:引号转义、字段内的逗号、不同的分隔符、值中的换行符。使用现成的库可以避免这些麻烦并处理边界情况。
CsvHelper 库——黄金标准
CsvHelper 是 .NET 中最流行的 CSV 处理库。它支持映射到 POCO 类、流式读取、分隔符和编码配置。
通过 NuGet 安装:
Install-Package CsvHelper读取 CSV 到对象列表的示例
using CsvHelper;using System.Globalization;
public class User{ public int Id { get; set; } public string Name { get; set; } public string Email { get; set; }}
var users = new List<User>();using (var reader = new StreamReader("users.csv"))using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)){ users = csv.GetRecords<User>().ToList();}从集合写入 CSV 的示例
using (var writer = new StreamWriter("output.csv"))using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)){ csv.WriteRecords(users);}内置解析器:TextFieldParser (Microsoft.VisualBasic)
如果您不想引入外部依赖,.NET 中有一个内置的 TextFieldParser,位于 Microsoft.VisualBasic.FileIO 命名空间中。它在 .NET Framework 和 .NET Core/.NET 5+ 中可用(需要安装 Microsoft.VisualBasic 包)。
TextFieldParser 使用示例
using Microsoft.VisualBasic.FileIO;
using (var parser = new TextFieldParser("data.csv")){ parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData) { string[] fields = parser.ReadFields(); Console.WriteLine(string.Join(" | ", fields)); }}优点:不需要第三方库。缺点:灵活性不如 CsvHelper,没有自动映射到类的功能。
处理大文件:流式处理
处理超过 100 MB 的 CSV 文件时,重要的是避免将整个文件加载到内存中。两个库都支持流式处理:
- CsvHelper — 在
foreach循环中使用GetRecords<T>(),不要调用.ToList()。 - TextFieldParser — 逐行读取,同样高效。
使用 CsvHelper 进行流式读取的示例
using (var reader = new StreamReader("large.csv"))using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)){ foreach (var record in csv.GetRecords<User>()) { ProcessUser(record); // 逐个处理 }}错误处理与数据验证
导入 CSV 时,数据可能不正确。CsvHelper 允许通过事件配置错误处理:
csv.Configuration.BadDataFound = context =>{ Console.WriteLine($"第 {context.RawRow} 行错误:{context.RawRecord}");};还可以使用属性进行字段验证:
public class Product{ [Name("ProductId")] public int Id { get; set; } [Required] public string Nam