c# - 使用 CsvHelper 将 csv 文件转换为 excel 时减少内存
问题描述
当我们使用具有 100K 行和 14 列的CSVHelper将 csv 文件转换为 excel 时,它需要 1.5GB 的进程内存。我们需要减少内存。这是 CsvHelper 的问题,占用了那么多内存来转换文件,还是我们在这里做错了什么。是否有解决方法来减少内存。
这是我正在使用的示例程序:
using ClosedXML.Excel;
using CsvHelper;
using System;
using System.Globalization;
using System.IO;
namespace ConsoleApp2.Conversion
{
public class CsvHelperExcelWriter
{
public void Process(string csvFilePath)
{
try
{
Stream ms = new MemoryStream();
using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
{
var _worksheet = workbook.AddWorksheet("Sheet1");
using (var csv = new CsvReader(new StreamReader(csvFilePath), CultureInfo.InvariantCulture))
{
csv.Read();
if (!string.IsNullOrWhiteSpace(csv.Context.Parser.RawRecord))
{
AddHeaders(csv, _worksheet);
AddValues(csv, _worksheet);
}
}
workbook.SaveAs(ms);
ms.Position = 0;
using (FileStream fileStream = new FileStream("C:\\Projects\\POC\\SampleFile\\Excel\\100000 Sales Records with CsvHelper.xlsx", FileMode.Append, FileAccess.Write))
{
ms.CopyTo(fileStream);
fileStream.Close();
}
}
}
catch (Exception)
{
throw;
}
}
private void AddValues(CsvReader csv, IXLWorksheet _worksheet)
{
int rowNumber = 2;
while (csv.Read())
{
int cellNumber = 1;
for (var i = 0; csv.TryGetField(i, out string value); i++)
{
_worksheet.Cell(rowNumber, cellNumber).SetValue(value);
cellNumber++;
}
rowNumber++;
}
}
private void AddHeaders(CsvReader csv, IXLWorksheet _worksheet)
{
int index = 1;
_ = csv.ReadHeader();
foreach (var header in csv.HeaderRecord)
{
_worksheet.Cell(1, index).Value = header;
index++;
}
}
}
}
解决方案
通常,高内存使用率是因为在创建 XLSX 文件时所有 Excel 库都使用最终 XML 序列化。为了解决这个问题,我创建了自己的SwiftExcel
库,将数据直接输出到文件中,省略了实际的 XML 序列化。
在您的情况下,我建议使用ExcelDataReader之类的高效工具读取 CSV,然后使用SwiftExcel输出。
这是一个例子。首先阅读您的 CSVExcelDataReader
并收集所有数据:
var list = new List<List<string>>();
using (var stream = File.Open("C:\\temp\\input.xlsx", FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateCsvReader(stream))
{
while (reader.Read())
{
var subList = new List<string>();
for (var i = 0; i < reader.FieldCount; i++)
{
subList.Add(reader.GetValue(i)?.ToString());
}
list.Add(subList);
}
}
}
现在使用以下命令将此数据输出到 Excel 中SwiftExcel
:
using (var ew = new ExcelWriter("C:\\temp\\test.xlsx"))
{
for (var row = 1; row <= list.Count; row++)
{
var subList = list[row-1];
for (var col = 1; col <= subList.Count; col++)
{
ew.Write(subList[col-1], col, row);
}
}
}
仍然存在内存问题,因为您首先收集所有 CSV 数据,但至少它没有使用 XML 序列化那么高。您可以尝试通过将这 2 个循环合并为一个并在读取时同时输出值来消除这种情况。
推荐阅读
- android - ExoPlayer:自定义音频处理器 - 均衡器
- capl - 在矢量 CANoe 中将 MeasurementIndex 重置为 0?
- android - 向下滚动回收站数据后变得分散
- microsoft-teams - 第三方应用程序是否可以视频通话团队用户?
- arrays - Behat 测试不会使用 json 数组在数据库上发送相同的信息
- flutter - Flutter Checkbox not changing/updating/working
- .htaccess - 如何从 .htaccess 文件中的 url 中删除斜杠?
- android - 如何在kotlin中设置按钮可见性
- javascript - 将国家/地区的 Javascript 数组映射到新数组中
- java - 有没有办法让 IBM JVM 使用标准 RFC 密码套件名称?