2013-03-05 66 views
4

我試圖用FileHelpers(http://www.filehelpers.net/)解析一個非常大的csv文件。該文件壓縮爲1GB,解壓縮大約20GB。FileHelpers在解析大型csv文件時拋出OutOfMemoryException

 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.Append(char值,的Int32 repeatCount) System.Text.StringBuilder.ExpandByABlock(的Int32 minBlockCharCount)在 System.Text.StringBuilder.Append(CHAR值) FileHelpers.StringHelper.ExtractQuotedString( LineInfo線,字符 quoteChar,布爾allowMultiline)留在在 FileHelpers.RecordInfo.StringToRecord(LineInfo線) FileHelpers.FieldBase.ExtractValue(LineInfo線) FileHelpers.DelimitedField.ExtractFieldString(LineInfo線)在 FileHelpers.FileHelperEngine 1.ReadStream(TextReader reader, Int32 maxRecords, DataTable dt) at FileHelpers.FileHelperEngine 1 .ReadStream(TextReader閱讀器)

是否有可能使用FileHelpers解析這個大文件?如果沒有人可以推薦一種解析文件的方法這麼大嗎?謝謝。

+0

BowserKingKoopa我的第一個問題是顯而易見的,當你解壓縮文件的時候有多少可用空間,如果它是20GB我會加倍看看你是否有40GB的空閒空間 – MethodMan 2013-03-05 20:32:55

+1

你想把大約20GB的數據放入RAM中嗎?真的嗎? – digEmAll 2013-03-05 20:34:48

+0

不應該使用BinaryReader而不是TextReader嗎? FileHelpers處理緩衝區大小還是你需要設置以及自己..? – MethodMan 2013-03-05 20:35:27

回答

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

如果你使用你只會被使用的時間記錄內存異步這種形式給出,那將更加快捷。

+2

謝謝! FileHelperAsyncEngine就是我正在尋找的。 – BowserKingKoopa 2013-03-06 15:06:09

+0

Flipn優秀的傢伙 – Eminem 2016-12-24 02:48:46

0

這不是一個完整的答案,但是如果你有一個20GB的csv文件,你需要20GB +將整個內容一次存儲在內存中,除非你的讀者將所有內容壓縮在內存中(不太可能)。你需要以塊的形式讀取這個文件,如果你沒有大量的內存,你將所有的東西放到一個數組中的解決方案將不起作用。

你需要一個循環更像這個有點:

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

C#的內存管理將是足夠聰明,你去通過他們來處理舊CSVItems的,只要你不保持對它們的引用掛在身邊。

如果你不關心處理順序,一個更好的版本會從CSV中讀取一個塊(例如10,000行),處理所有這些,然後獲得另一個塊,或爲DoWhatINeedWithCsvRow創建一個任務。