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

时间:2013-03-05 20:29:30

标签: c# csv filehelpers

我正在尝试使用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解析这么大的文件?如果没有,任何人都可以推荐一种解析文件的方法吗?感谢。

2 个答案:

答案 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创建任务。