C# FileHelpers在解析大型csv文件时抛出OutOfMemoryException
我正试图用FileHelpers()解析一个非常大的csv文件。该文件压缩为1GB,解压为20GBC# FileHelpers在解析大型csv文件时抛出OutOfMemoryException,c#,csv,filehelpers,C#,Csv,Filehelpers,我正试图用FileHelpers()解析一个非常大的csv文件。该文件压缩为1GB,解压为20GB string fileName = @"c:\myfile.csv.gz"; using (var fileStream = File.OpenRead(fileName)) { using (GZipStream gzipStream = new GZipStream(fileStream, CompressionMode.
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);
}
}
}
stringfilename=@“c:\myfile.csv.gz”;
使用(var fileStream=File.OpenRead(文件名))
{
使用(GZipStream GZipStream=newgzipstream(fileStream,CompressionMode.decompresse,false))
{
使用(TextReader TextReader=newstreamReader(gzipStream))
{
var engine=new FileHelperEngine();
CSVItem[]items=engine.ReadStream(textReader);
}
}
}
然后FileHelpers抛出OutOfMemoryException
测试失败:“System.OutOfMemoryException”类型的异常为
扔。System.OutOfMemoryException:类型为的异常
已引发“System.OutOfMemoryException”。在
System.Text.StringBuilder.ExpandByABlock(Int32 minBlockCharCount)位于
System.Text.StringBuilder.Append(字符值,Int32 repeatCount)位于
System.Text.StringBuilder.Append(字符值)位于
FileHelpers.StringHelper.ExtractQuotedString(LineInfo行,字符
quoteChar,布尔allowMultiline)在
FileHelpers.DelimitedField.ExtractFieldString(LineInfo行)位于
FileHelpers.FieldBase.ExtractValue(LineInfo行)位于
FileHelpers.RecordInfo.StringToRecord(LineInfo行)位于
FileHelpers.FileHelperEngine1.ReadStream(文本阅读器,Int32
maxRecords,数据表dt)位于
FileHelpers.FileHelperEngine
1.ReadStream(文本阅读器)
可以用FileHelper解析这么大的文件吗?如果没有,谁能推荐一种方法来解析这么大的文件?谢谢。这不是一个完整的答案,但是如果你有一个20GB的csv文件,你将需要20GB+来一次性将整个内容存储在内存中,除非你的阅读器将所有内容都压缩在内存中(不太可能)。您需要分块读取文件,如果没有大量ram,那么将所有内容放入阵列的解决方案将无法工作 您需要一个更像这样的循环:
CsvReader reader = new CsvReader(filePath)
CSVItem item = reader.ReadNextItem();
while(item != null){
DoWhatINeedWithCsvRow(item);
item = reader.ReadNextItem();
}
C#的内存管理将足够智能,可以在您浏览旧的Csvitem时处理它们,前提是您不保留对它们的引用
更好的版本是从CSV中读取一个区块(例如10000行),处理所有这些区块,然后获取另一个区块,或者为DoWhatINeedWithCsvRow创建一个任务,如果您不关心处理顺序的话。您必须以这种方式逐个记录地工作:
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
}
}
}
}
}
stringfilename=@“c:\myfile.csv.gz”;
使用(var fileStream=File.OpenRead(文件名))
{
使用(GZipStream GZipStream=newgzipstream(fileStream,CompressionMode.decompresse,false))
{
使用(TextReader TextReader=newstreamReader(gzipStream))
{
var engine=new FileHelperAsyncEngine();
使用(engine.BeginReadStream(文本阅读器))
{
foreach(发动机中的var记录)
{
//处理每个项目
}
}
}
}
}
如果使用这种异步方法,一次只能使用一条记录的内存,速度会快得多。BowserKingKoopa我的第一个问题很明显,解压文件时有多少可用空间如果是20GB,我会加倍,看看是否有40GB的空闲空间。是否要将~20GB的数据放入RAM?真的吗?你不应该用二进制阅读器而不是文本阅读器吗?FileHelper是否处理缓冲区大小,或者您是否需要自己设置缓冲区大小?在我看来,这是您应该使用数据库处理的事情(因此实际数据将保留在HD上)。。。例如,为什么不创建sqlite数据库并将该CSV导入到表中呢?谢谢!FileHelperAsyncEngine正是我想要的。