我正在尝试使用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>();
CSVItem[] items = engine.ReadStream(textReader);
}
}
}
FileHelpers然后抛出OutOfMemoryException。
测试失败:'System.OutOfMemoryException'类型的异常是 抛出。 System.OutOfMemoryException:类型的异常 抛出'System.OutOfMemoryException'。在 System.Text.StringBuilder.ExpandByABlock(Int32 minBlockCharCount)at System.Text.StringBuilder.Append(Char值,Int32 repeatCount)at System.Text.StringBuilder.Append(Char值)at FileHelpers.StringHelper.ExtractQuotedString(LineInfo line,Char quoteChar,Boolean allowMultiline)at FileHelpers.DelimitedField.ExtractFieldString(LineInfo line)at FileHelpers.FieldBase.ExtractValue(LineInfo行)at FileHelpers.RecordInfo.StringToRecord(LineInfo line)at FileHelpers.FileHelperEngine
1.ReadStream(TextReader reader, Int32 maxRecords, DataTable dt) at FileHelpers.FileHelperEngine
1.ReadStream(TextReader reader)
是否可以使用FileHelpers解析这么大的文件?如果没有,任何人都可以推荐一种解析文件的方法吗?感谢。
答案 0 :(得分:9)
您必须以这种方式记录记录:
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<CSVItem>();
using(engine.BeginReadStream(textReader))
{
foreach(var record in engine)
{
// Work with each item
}
}
}
}
}
如果您使用此async aproach,您将只使用内存进行一次记录,这样会更快。
答案 1 :(得分:0)
这不是一个完整的答案,但是如果你有一个20GB的csv文件,你需要20GB +才能将整个内容一次性存储在内存中,除非你的阅读器将所有内容压缩在内存中(不太可能)。您需要以块的形式读取文件,如果没有大量的ram,那么将所有内容放入数组中的解决方案将无效。
你需要一个更像这样的循环:
CsvReader reader = new CsvReader(filePath)
CSVItem item = reader.ReadNextItem();
while(item != null){
DoWhatINeedWithCsvRow(item);
item = reader.ReadNextItem();
}
C#的内存管理将足够聪明,可以在您通过它们时处理旧的CSVItems,前提是您没有保留对它们的引用。
更好的版本会读取CSV中的一个块(例如10,000行),处理所有这些,然后获取另一个块,或者如果您不关心处理顺序,则为DoWhatINeedWithCsvRow创建任务。