csv拼接需转义特殊字符并加bom:字段含逗号、双引号或换行时须用双引号包裹且内部双引号转义为两个;多行数据需逐行逐字段转义;utf-8文件须带bom才能被excel正确识别中文。

用 string.Join 拼接最简单,但得先处理特殊字符
直接 string.Join(",", list) 看似省事,实际只要列表里有含逗号、换行或双引号的字符串,生成的 CSV 就会错位甚至被 Excel 误解析。CSV 不是“用逗号连起来就行”,它有明确转义规则:字段含 ,、" 或换行时,必须用双引号包裹,且内部的双引号要变成两个双引号("")。
实操建议:
- 别自己手写转义逻辑——容易漏掉换行符或嵌套引号
- 对每个字段调用一个安全包装函数,比如:
static string ToCsvField(string s) => string.IsNullOrEmpty(s) ? "" : $"\"{s.Replace("\"", "\"\"")}\""; - 再用
string.Join拼接:var csvLine = string.Join(",", list.Select(ToCsvField));
导出多行数据时,每行都要单独转义,不能只处理一维
很多人把 List<string></string> 当成单行处理,但真实场景常是 List<person></person> 这类对象列表,需要按属性提取后逐行转为 CSV 字符串。这时候如果直接 list.Select(x => x.Name + "," + x.Email),照样会崩在邮箱含 @ 或姓名带逗号的情况。
实操建议:
- 先投影成字符串数组(每行一个
string[]),再逐字段转义:var rows = people.Select(p => new string[] { p.Name, p.Email, p.Phone }); - 对每行执行字段转义+拼接:
var csvLines = rows.Select(row => string.Join(",", row.Select(ToCsvField))); - 最后用
Environment.NewLine连接所有行:var fullCsv = string.Join(Environment.NewLine, csvLines);
别忽略编码问题:UTF-8 带 BOM 才能被 Excel 正确识别中文
用 Encoding.UTF8.GetBytes(csvString) 写文件后,Excel 打开中文全乱码?不是代码错了,是缺 BOM。Windows 下 Excel 默认把无 BOM 的 UTF-8 当作 ANSI 编码读。
实操建议:
- 生成字符串后,用
Encoding.UTF8的带 BOM 版本编码:var bom = Encoding.UTF8.GetPreamble(); // 得到 3 字节 BOM
- 拼接时前置 BOM:
var bytes = Encoding.UTF8.GetBytes(fullCsv);
var withBom = bom.Concat(bytes).ToArray();
- 或者更简单:用
new StreamWriter(path, false, new UTF8Encoding(true)),第二个true表示写 BOM
复杂对象导出推荐用 CsvHelper,但小项目别为它加依赖
CsvHelper 能自动处理类型映射、引用类型、集合嵌套、自定义分隔符,还支持异步和流式写入。但它引入了额外依赖,编译体积增加,且配置稍重——就导出 5 行用户昵称,真没必要。
实操建议:
- 纯内存拼接、字段少、无嵌套:坚持手写
ToCsvField+string.Join,清晰可控 - 要导出数据库查询结果、含日期/数字/空值、可能扩展成导出 Excel:直接上
CsvHelper,避免后期反复修 CSV 边界逻辑 - 注意
CsvHelper默认不写 BOM,仍需手动设置:var config = new CsvConfiguration(CultureInfo.InvariantCulture) { ShouldUseCustomCharset = true };再配合UTF8Encoding(true)构造 writer











