解析大型csv文件时,FileHelpers会抛出OutOfMemoryException

我正在尝试使用FileHelpers( http://www.filehelpers.net/ )解析一个非常大的csv文件。 该文件为1GB压缩文件,解压缩约20GB。

string fileName = @"c:\myfile.csv.gz"; using (var fileStream = File.OpenRead(fileName)) { using (GZipStream gzipStream = new GZipStream(fileStream, CompressionMode.Decompress, false)) { using (TextReader textReader = new StreamReader(gzipStream)) { var engine = new FileHelperEngine(); CSVItem[] items = engine.ReadStream(textReader); } } } 

FileHelpers然后抛出OutOfMemoryException。

测试失败:抛出了类型’System.OutOfMemoryException’的exception。 System.OutOfMemoryException:抛出了类型’System.OutOfMemoryException’的exception。 位于System.Text.StringBuilder.Append(Char值)的System.Text.StringBuilder.ExpandByABlock(Int32 minBlockCharCount)位于FileHelpers.StringHelper.ExtractQuotedString的System.Text.StringBuilder.Append(Char值)(LineInfo line,Char在FileHelpers.FileHelperEngine的FileHelpers.RecordInfo.StringToRecord(LineInfo行)的FileHelpers.FieldBase.ExtractValue(LineInfo行)的FileHelpers.DelimitedField.ExtractFieldString(LineInfo行)处的quoteChar,Boolean allowMultiline) 1.ReadStream(TextReader reader, Int32 maxRecords, DataTable dt) at FileHelpers.FileHelperEngine 1.ReadStream(TextReader reader)

是否可以使用FileHelpers解析这么大的文件? 如果没有,任何人都可以推荐一种解析文件的方法吗? 谢谢。

您必须以这种方式记录记录:

  string fileName = @"c:\myfile.csv.gz"; using (var fileStream = File.OpenRead(fileName)) { using (GZipStream gzipStream = new GZipStream(fileStream, CompressionMode.Decompress, false)) { using (TextReader textReader = new StreamReader(gzipStream)) { var engine = new FileHelperAsyncEngine(); using(engine.BeginReadStream(textReader)) { foreach(var record in engine) { // Work with each item } } } } } 

如果你使用这个async aproach,你只会使用内存进行一次记录,而且速度会快得多。

这不是一个完整的答案,但是如果你有一个20GB的csv文件,你需要20GB +才能将整个内容一次性存储在内存中,除非你的阅读器将所有内容压缩在内存中(不太可能)。 您需要以块的forms读取文件,如果没有大量的ram,那么将所有内容放入数组中的解决方案将无法正常工作。

你需要一个更像这样的循环:

 CsvReader reader = new CsvReader(filePath) CSVItem item = reader.ReadNextItem(); while(item != null){ DoWhatINeedWithCsvRow(item); item = reader.ReadNextItem(); } 

C#的内存管理将足够智能,可以在您通过它们时处理旧的CSVItems,前提是您不要保留对它们的引用。

更好的版本会读取CSV中的块(例如10,000行),处理所有这些块,然后获取另一个块,或者如果您不关心处理顺序,则为DoWhatINeedWithCsvRow创建任务。