如何将对象列表转换为CSV并压缩?现有代码问题求助
问题分析与解决方案
当前代码的核心问题
- CSV生成逻辑完全错误:使用
BinaryFormatter序列化对象是二进制序列化,生成的是二进制数据,并非文本格式的CSV,这直接导致文件打开后出现乱码、无关内容。 - 未实现拆分逻辑:循环遍历所有数据但仅生成了一个
SourceFile实例,完全未按需求拆分多个CSV文件。 - Controller存在语法错误:
foreach(SourceFile sf in sourceFile)中的sourceFile应为sourceFiles;sd.Extension应为sf.Extension;bytes变量未赋值,最终返回的FileBytes未定义,代码无法正常运行。
最佳实现方案
1. 依赖选择(推荐)
使用CsvHelper库处理CSV序列化,它能自动处理对象到CSV的映射,避免手动拼接的格式错误,NuGet安装命令:Install-Package CsvHelper
2. 修正Service层(实现CSV生成+拆分)
按指定条数拆分数据,为每个子集生成对应的CSV字节流:
using CsvHelper; using System.Globalization; public IEnumerable<SourceFile> PrepareData(List<XXXData> data, int splitSize = 1000) // splitSize为每个CSV的最大行数 { var result = new List<SourceFile>(); var archiveName = "Test_"; int fileIndex = 1; // 拆分数据并生成CSV for (int i = 0; i < data.Count; i += splitSize) { var chunk = data.Skip(i).Take(splitSize).ToList(); using (var ms = new MemoryStream()) using (var writer = new StreamWriter(ms)) using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csvWriter.WriteHeader<XXXData>(); csvWriter.NextRecord(); csvWriter.WriteRecords(chunk); writer.Flush(); result.Add(new SourceFile { Name = $"{archiveName}{fileIndex}", Extension = "csv", FileBytes = ms.ToArray() }); fileIndex++; } } return result; }
3. 修正Controller层(修复语法错误+完善Zip逻辑)
IActionResult GetDados() { var list = _itensService.GetDadosXXX().ToList(); var sourceFiles = _itensService.PrepareData(list); // 可自定义拆分大小,如PrepareData(list, 500) using (MemoryStream ms = new MemoryStream()) { using (ZipArchive zip = new ZipArchive(ms, ZipArchiveMode.Create, true)) { foreach(SourceFile sf in sourceFiles) { ZipArchiveEntry zipItem = zip.CreateEntry($"{sf.Name}.{sf.Extension}"); using (MemoryStream fileMemoryStream = new MemoryStream(sf.FileBytes)) using (Stream entryStream = zipItem.Open()) { fileMemoryStream.CopyTo(entryStream); } } } ms.Position = 0; var zipBytes = ms.ToArray(); return File(zipBytes, "application/zip", "ZipArchiveTest.zip"); } }
4. 手动实现CSV(不依赖第三方库)
若不想使用第三方库,可手动拼接CSV内容,注意处理特殊字符:
public IEnumerable<SourceFile> PrepareData(List<XXXData> data, int splitSize = 1000) { var result = new List<SourceFile>(); var archiveName = "Test_"; int fileIndex = 1; // 生成表头 var header = string.Join(",", typeof(XXXData).GetProperties().Select(p => p.Name)); for (int i = 0; i < data.Count; i += splitSize) { var chunk = data.Skip(i).Take(splitSize).ToList(); var csvContent = new StringBuilder(); csvContent.AppendLine(header); foreach (var item in chunk) { // 拼接每行数据,处理含逗号/引号的字段 var fields = typeof(XXXData).GetProperties().Select(p => { var value = p.GetValue(item)?.ToString() ?? string.Empty; if (value.Contains(',') || value.Contains('"')) { return $"\"{value.Replace("\"", "\"\"")}\""; } return value; }); csvContent.AppendLine(string.Join(",", fields)); } var fileBytes = Encoding.UTF8.GetBytes(csvContent.ToString()); result.Add(new SourceFile { Name = $"{archiveName}{fileIndex}", Extension = "csv", FileBytes = fileBytes }); fileIndex++; } return result; }
总结
当前思路的核心方向完全错误,错误使用二进制序列化生成CSV,且未实现拆分逻辑。修正后通过正确的CSV序列化(第三方库或手动拼接)+ 数据拆分+ 修复语法错误,即可实现需求。
内容的提问来源于stack exchange,提问作者Pedro Martins
相关产品推荐
相关产品推荐

