使用csv helper将csv文件转换为excel时减少内存



当我们使用CSVHelper将csv文件转换为excel时对于100K行和14列,它需要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++;
}
}
}
}

我不熟悉c#。但如果我猜出问题,它可能会一次读取所有内容,并将其保存在内存中。您应该使用某种缓冲方法,其中整个csv文件不会一次加载到内存中。一旦你转换csv行,你必须确保你立即输出到excel文件和丢弃csv行(不存储在任何数组/列表),这样它可以被垃圾收集器拾取。

通常高内存占用是由于所有Excel库在创建XLSX文件时使用的最终XML序列化。为了解决这个问题,我最后创建了自己的SwiftExcel库,它直接将数据输出到文件,而省略了实际的XML序列化。

在您的情况下,我建议使用ExcelDataReader等高效工具读取CSV,然后使用SwiftExcel输出。

下面是一个例子。首先使用ExcelDataReader读取CSV并收集所有数据:

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);
}
}
} 

现在使用SwiftExcel将此数据输出到Excel中:

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序列化那么高。您可以尝试通过将这两个循环合并为一个并在读取时同时输出值来消除这种情况。

相关内容

  • 没有找到相关文章

最新更新