在C#开发中,CSV文件因为格式简单、兼容性好,常被用来存储结构化数据,掌握其读写方法是开发者的基础技能。下面会介绍多种实现方式,满足不同场景的需求。

基础方式:使用StreamReader和StreamWriter读写
如果不想引入第三方依赖,使用C#自带的StreamReader和StreamWriter类就可以完成基础的CSV读写操作,适合处理格式简单、没有复杂特殊字符的CSV文件。
读取CSV文件
读取时按行读取文件内容,再根据逗号分隔每一行的字段即可,需要注意如果字段中包含逗号或者换行符,通常会用双引号包裹字段,这种情况需要做额外处理。
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
public class CsvHelper
{
// 读取CSV文件,返回每行字段的列表
public static List<string[]> ReadCsv(string filePath)
{
List<string[]> result = new List<string[]>();
// 使用UTF8编码读取,避免中文乱码
using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// 简单按逗号分割,未处理字段带引号的情况
string[] fields = line.Split(',');
result.Add(fields);
}
}
return result;
}
}
写入CSV文件
写入时只需要将每个字段用逗号拼接,然后逐行写入文件即可,如果字段中包含逗号,需要给字段加上双引号包裹。
using System;
using System.IO;
using System.Text;
public class CsvHelper
{
// 写入CSV文件,data是每行字段的集合
public static void WriteCsv(string filePath, List<string[]> data)
{
using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
foreach (var row in data)
{
List<string> processedFields = new List<string>();
foreach (var field in row)
{
// 如果字段包含逗号,用双引号包裹
if (field.Contains(","))
{
processedFields.Add($""{field}"");
}
else
{
processedFields.Add(field);
}
}
// 用逗号拼接所有字段,写入一行
writer.WriteLine(string.Join(",", processedFields));
}
}
}
}
处理复杂CSV场景
如果CSV文件中存在字段包含双引号、换行符等复杂情况,基础的分割方式就会失效,这时候需要更严谨的解析逻辑,或者引入成熟的第三方库。
自定义解析复杂CSV
当字段被双引号包裹时,内部的逗号不会被当作分隔符,双引号本身需要用两个双引号转义,比如字段内容是He said "Hello",在CSV中会写成"He said ""Hello"""。
using System;
using System.Collections.Generic;
using System.Text;
public class AdvancedCsvParser
{
// 解析单行CSV内容,处理引号和转义
public static string[] ParseCsvLine(string line)
{
List<string> fields = new List<string>();
StringBuilder currentField = new StringBuilder();
bool inQuotes = false;
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
if (inQuotes)
{
// 如果在引号内,遇到两个双引号表示一个转义的双引号
if (c == '"' && i + 1 < line.Length && line[i + 1] == '"')
{
currentField.Append('"');
i++; // 跳过下一个双引号
}
else if (c == '"')
{
// 引号结束
inQuotes = false;
}
else
{
currentField.Append(c);
}
}
else
{
if (c == '"')
{
// 进入引号包裹的字段
inQuotes = true;
}
else if (c == ',')
{
// 字段分隔,保存当前字段
fields.Add(currentField.ToString());
currentField.Clear();
}
else
{
currentField.Append(c);
}
}
}
// 保存最后一个字段
fields.Add(currentField.ToString());
return fields.ToArray();
}
}
使用第三方库CsvHelper
实际开发中更推荐使用成熟的第三方库,比如NuGet上的CsvHelper,它已经处理了所有复杂的CSV格式场景,使用起来非常简单。
首先通过NuGet安装CsvHelper包,然后就可以快速实现读写:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using CsvHelper;
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class CsvHelperDemo
{
// 读取CSV到对象列表
public static List<User> ReadCsvWithLibrary(string filePath)
{
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
return new List<User>(csv.GetRecords<User>());
}
}
// 写入对象列表到CSV
public static void WriteCsvWithLibrary(string filePath, List<User> users)
{
using (var writer = new StreamWriter(filePath))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(users);
}
}
}
注意事项
- 读写CSV时尽量指定编码为UTF8,避免出现中文乱码问题,尤其是跨系统传输的CSV文件。
- 如果CSV文件第一行是表头,读取时可以选择跳过第一行,或者将表头和对象属性映射。
- 处理大文件时,不要一次性将所有内容加载到内存,建议使用流逐行处理,减少内存占用。
- 如果字段中包含换行符,基础的分行读取会失效,需要结合引号状态判断一行是否结束。
C#CSV读写StreamReaderStreamWriterFile_Stream修改时间:2026-07-14 22:09:39