You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现xlsx转csv时字段含逗号被错误拆分的问题

问题描述

我正尝试通过如下代码实现xlsx文件转csv功能:

public static bool saveAsCsv(string excelFilePath, string destinationCsvPath)
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        
        using (var stream = new FileStream(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            IExcelDataReader? reader = null;

            if (excelFilePath.EndsWith(".xls"))
            {
                reader = ExcelReaderFactory.CreateBinaryReader(stream);
            }
            else if (excelFilePath.EndsWith(".xlsx"))
            {
                reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
            }

            if (reader == null)
                return false;

            var ds = reader.AsDataSet(new ExcelDataSetConfiguration()
            {
                ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
                {
                    UseHeaderRow = false
                }
            });

            var csvContent = string.Empty;
            int row_no = 0;
            while (row_no < ds.Tables[0].Rows.Count)
            {
                var arr = new List<string>();
                for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
                {
#pragma warning disable CS8604 // Possible null reference argument.
                        arr.Add(ds.Tables[0].Rows[row_no][i].ToString());
#pragma warning restore CS8604 // Possible null reference argument.
                }
                row_no++;
                csvContent += string.Join(",", arr) + "\n";
            }

            StreamWriter csv = new StreamWriter(destinationCsvPath, false);
            csv.Write(csvContent);
            csv.Close();
            return true;
        }
    }

上述代码可正常运行,但存在一个问题:当字段内容本身包含逗号分隔的两个值时,会被识别为两个独立字段。
举例如下:

本应处于同一个字段内的内容:
Test A, test B
转换后该内容被拆分到了不同字段中,需要修改代码避免该问题。

问题根因

当前实现没有遵循标准CSV格式的转义规则:

  • 若字段内容包含逗号、换行符、半角双引号,必须用半角双引号将整个字段包裹
  • 若字段本身包含半角双引号,需要将单个双引号替换为两个连续双引号做转义
    直接用逗号拼接未转义的原始字段值,遇到内容自带逗号的场景自然会被CSV解析器识别为字段分隔符,造成拆分错误。
修复方案

方案1:补充标准CSV转义逻辑(无需新增依赖)

先实现专门的字段转义方法处理所有特殊字符场景,同时优化原代码的资源释放、字符串拼接效率、编码指定问题,修改后的完整代码如下:

/// <summary>
/// 按CSV标准规则转义单个字段
/// </summary>
private static string EscapeCsvField(string fieldValue)
{
    if (string.IsNullOrEmpty(fieldValue))
        return string.Empty;
    
    // 存在特殊字符时,用双引号包裹字段,同时转义字段内的双引号
    if (fieldValue.Contains(',') || fieldValue.Contains('"') || 
        fieldValue.Contains('\n') || fieldValue.Contains('\r'))
    {
        return $"\"{fieldValue.Replace("\"", "\"\"")}\"";
    }

    return fieldValue;
}

public static bool saveAsCsv(string excelFilePath, string destinationCsvPath)
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    
    using (var stream = new FileStream(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        IExcelDataReader? reader = null;

        if (excelFilePath.EndsWith(".xls"))
        {
            reader = ExcelReaderFactory.CreateBinaryReader(stream);
        }
        else if (excelFilePath.EndsWith(".xlsx"))
        {
            reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
        }

        if (reader == null)
            return false;

        using (reader)
        {
            var ds = reader.AsDataSet(new ExcelDataSetConfiguration()
            {
                ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
                {
                    UseHeaderRow = false
                }
            });

            var dataTable = ds.Tables[0];
            // 用StringBuilder代替字符串累加,提升大文件处理效率
            var csvBuilder = new StringBuilder();
            
            for (int rowNo = 0; rowNo < dataTable.Rows.Count; rowNo++)
            {
                var rowFields = new List<string>();
                for (int colNo = 0; colNo < dataTable.Columns.Count; colNo++)
                {
                    string fieldValue = dataTable.Rows[rowNo][colNo]?.ToString() ?? string.Empty;
                    // 对每个字段做转义后再加入行数据
                    rowFields.Add(EscapeCsvField(fieldValue));
                }
                csvBuilder.AppendLine(string.Join(",", rowFields));
            }

            // 指定UTF-8编码写入,避免Excel打开乱码,用using自动释放资源
            using (var csvWriter = new StreamWriter(destinationCsvPath, false, Encoding.UTF8))
            {
                csvWriter.Write(csvBuilder.ToString());
            }

            return true;
        }
    }
}

方案2:使用成熟CSV库(适合复杂场景)

如果后续需要处理更多CSV边缘场景(比如不同分隔符、自定义转义规则、超大文件流式写入),可以直接引入专门的CSV处理库代替手动拼接,从根源上避免转义逻辑写漏的问题。

注意事项
  • 所有字段都建议走转义逻辑,不要只判断当前已知的特殊字符场景,避免后续数据变化出现兼容问题
  • 写入文件时明确指定编码,优先使用带BOM的UTF-8,避免Windows下用Excel打开CSV出现中文乱码
  • 文件流、DataReader、写入器这类资源都要放在using块中,自动完成资源释放,避免文件占用、内存泄漏问题
  • 大文件转换场景不要把全部内容拼接到内存字符串中,建议逐行读取逐行写入,降低内存占用

内容的提问来源于stack exchange,提问作者lross15

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 23:18:15