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

.NET C#无第三方包实现Excel转CSV:上传后转码异常求助

问题根源

你的ConvertExcelToCsv方法逻辑完全错误:Excel文件(不管是.xlsx还是.xls)都是二进制格式,不是纯文本的制表符分隔文件。直接读取文件字节并转换为字符拼接,只会得到乱码(你看到的"字节码"),根本无法提取表格数据。

解决方案

针对.xlsx格式(推荐限制用户上传该格式,因为.xls的BIFF格式手动解析复杂度极高),我们可以利用其本质是ZIP压缩包的特性,手动解压后读取内部XML文件提取表格数据,再转换为CSV:

修改后的完整代码

using System.IO.Compression;
using System.Xml.Linq;

public void document_excel_OnFileUploaded_Staff(object sender, FileUploadedEventArgs e)
{
    fu_documents_Staff.TargetFolder = "~/UploadedFiles";
    DataTable dt = obj_common.Get_File_Code("CustDoc");
    if (dt.Rows.Count > 0 && dt.Rows[0][0].ToString() != "")
    {
        string files_name = dt.Rows[0][0].ToString() + e.File.GetNameWithoutExtension().ToString() + e.File.GetExtension();
        string filePath = Path.Combine(Server.MapPath(fu_documents_Staff.TargetFolder), files_name);

        // Save the uploaded file
        e.File.SaveAs(filePath);

        string csvFilePath = string.Empty;
        try
        {
            // Convert Excel to CSV
            csvFilePath = ConvertExcelToCsv(filePath);

            // Read the data from CSV
            using (StreamReader reader = new StreamReader(csvFilePath))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                    string[] values = line.Split(',');

                    // Process the data as needed
                    foreach (string value in values)
                    {
                        Console.WriteLine(value);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"转换失败:{ex.Message}");
        }
        finally
        {
            // Cleanup the CSV file if it exists
            if (!string.IsNullOrEmpty(csvFilePath) && File.Exists(csvFilePath))
            {
                File.Delete(csvFilePath);
            }
        }

        hdn_doc_name_Staff.Value = e.File.GetNameWithoutExtension().ToString() + e.File.GetExtension();
        hdn_doc_sav_Staff.Value = files_name;
        lab_doc_name_out_Staff.Text = hdn_doc_name_Staff.Value;
    }
}

private string ConvertExcelToCsv(string excelFilePath)
{
    string csvFilePath = Path.ChangeExtension(excelFilePath, ".csv");
    string extension = Path.GetExtension(excelFilePath).ToLower();

    if (extension == ".xlsx")
    {
        // .xlsx是ZIP压缩包,读取内部XML提取数据
        using (ZipArchive zipArchive = ZipFile.OpenRead(excelFilePath))
        {
            // 获取第一个工作表的XML文件(默认sheet1.xml)
            ZipArchiveEntry sheetEntry = zipArchive.GetEntry("xl/worksheets/sheet1.xml");
            if (sheetEntry == null)
            {
                throw new InvalidOperationException("未找到工作表文件");
            }

            using (StreamReader sheetReader = new StreamReader(sheetEntry.Open()))
            {
                XDocument sheetDoc = XDocument.Parse(sheetReader.ReadToEnd());
                XNamespace ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";

                using (StreamWriter csvWriter = new StreamWriter(csvFilePath))
                {
                    // 遍历所有行
                    foreach (XElement row in sheetDoc.Descendants(ns + "row"))
                    {
                        StringBuilder csvLine = new StringBuilder();
                        bool isFirstCell = true;

                        // 遍历行内所有单元格
                        foreach (XElement cell in row.Descendants(ns + "c"))
                        {
                            if (!isFirstCell)
                            {
                                csvLine.Append(',');
                            }
                            isFirstCell = false;

                            string cellValue = cell.Element(ns + "v")?.Value ?? string.Empty;

                            // 处理共享字符串(单元格类型为"s"时引用共享字符串表)
                            if (cell.Attribute("t")?.Value == "s")
                            {
                                ZipArchiveEntry sharedStringEntry = zipArchive.GetEntry("xl/sharedStrings.xml");
                                if (sharedStringEntry != null)
                                {
                                    using (StreamReader ssReader = new StreamReader(sharedStringEntry.Open()))
                                    {
                                        XDocument ssDoc = XDocument.Parse(ssReader.ReadToEnd());
                                        XElement stringItem = ssDoc.Descendants(ns + "si").ElementAt(int.Parse(cellValue));
                                        cellValue = stringItem.Descendants(ns + "t").FirstOrDefault()?.Value ?? string.Empty;
                                    }
                                }
                            }

                            // 处理包含逗号或引号的内容,用双引号包裹并转义内部引号
                            if (cellValue.Contains(',') || cellValue.Contains('"'))
                            {
                                csvLine.Append('"').Append(cellValue.Replace("\"", "\"\"")).Append('"');
                            }
                            else
                            {
                                csvLine.Append(cellValue);
                            }
                        }

                        csvWriter.WriteLine(csvLine.ToString());
                    }
                }
            }
        }
    }
    else if (extension == ".xls")
    {
        // .xls为BIFF二进制格式,手动解析复杂度极高,暂不支持
        throw new NotSupportedException("暂不支持解析.xls格式文件,请上传.xlsx文件");
    }
    else
    {
        throw new ArgumentException("上传的文件不是有效的Excel文件");
    }

    return csvFilePath;
}

关键说明

  1. 核心逻辑:.xlsx本质是包含多个XML文件的ZIP包,我们通过ZipFile解压读取工作表XML和共享字符串XML,提取单元格数据并转换为CSV格式。
  2. 注意事项:
    • 仅处理第一个工作表(sheet1.xml),如需处理其他工作表,需修改查找工作表入口的逻辑。
    • 处理了共享字符串(Excel会将重复字符串存入共享表,单元格仅存索引)。
    • 对包含逗号或引号的单元格内容做了CSV格式兼容处理。
    • 若必须支持.xls格式,建议调整需求或寻找其他兼容方案(但纯手动解析几乎不现实)。
  3. 依赖:确保项目引用System.IO.Compression.FileSystem(.NET Framework需手动添加引用,.NET Core/5+默认包含)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:52:22