2017-08-07 64 views
0

我使用CSV閱讀器,發現解析數據需要很多時間。我怎麼能加載整個csv文件到內存,然後按記錄處理它,因爲我必須自定義映射記錄。如何完全加載文件並處理記錄csvreader?

TextReader tr = new StreamReader(File.Open(@"C:\MarketData\" + symbol + ".txt", FileMode.Open)); 
    CsvReader csvr = new CsvReader(tr); 
    while (csvr.Read()) 
{ 
// do your magic 
} 
+0

好的.NET流已經使用緩衝,所以你確定這是問題嗎?文件有多大?您可能想嘗試** async **方法 – MickyD

+0

其每個文件大約10 MB – junkone

回答

0

要直接回答您的問題:您可以將文件完全加載到內存流中,然後使用您的CsvReader從該流重新讀取。同樣,你可以爲你的文件流創建一個更大的讀緩衝區,例如15MB,這將在整個文件中讀取整個文件到緩衝區。我懷疑這其中的任何一個都不會改善10MB文件的性能。

找到真正的性能瓶頸:從磁盤讀取文件內容的時間,將CSV解析爲字段的時間,還是處理記​​錄的時間?一個10MB的文件看起來非常小。我使用自定義csv閱讀器處理250MB + csv文件的集合,沒有任何投訴。

如果處理是瓶頸,並且您有多個可用線程並且您的csv文件格式不需要支持轉義換行符,那麼您可以將整個文件讀入行列表(System.IO.File.ReadAllLines/.ReadLines)並使用不同的任務解析每一行。例如:

System.IO.File.ReadLines() 
.Skip(1)     // header line. Assume trusted to be correct. 
.AsParallel() 
.Select(ParseRecord)  // RecordClass ParseRecord(string line) 
.ForAll(ProcessRecord); // void ProcessRecord(RecordClass) 

如果你有很多文件解析,可以處理不同任務中的每個文件,並使用異步方法來最大限度地提高吞吐量。如果它們都來自同一個物理磁盤,那麼你的milage會有所不同,甚至可能比單線程方法更糟糕。

更先進:

如果您知道您的文件包含8位字符而已,那麼你就可以在字節數組操作,跳過StreamReader的開銷投字節到字符。通過這種方式,您可以在一次調用中將整個文件讀入一個字節數組,並假設不需要支持換行符轉義,就可以掃描換行符。在這種情況下,掃描換行符可以由多個線程完成,每個線程都查看字節數組的一部分。

如果您不需要支持字段轉義(a,「b,c」,d),那麼您可以編寫更快的解析器,只需查找字段分隔符(通常爲逗號)即可。如果存在瓶頸,您也可以將字段分界解析和字段內容解析分割爲線程,但內存訪問局部性可能會否定任何好處。

在某些情況下,您可能不需要將字段解析爲中間數據結構(例如雙精度,字符串),並且可以直接處理對字段開始/結尾的引用並節省一些中間數據結構的創建時間。

4

創建一個完全代表/鏡像CSV文件的類。然後將所有內容讀入該類的列表中。以下片段來自CsvHelper的文檔。

var csv = new CsvReader(textReader); 
var records = csv.GetRecords<MyClass>().ToList(); 

的重要組成部分,是.ToList(),因爲這將迫使所有的數據加載到你的列表中,而不是產生結果,當您訪問它們。

然後,您可以在該列表上執行額外的映射/提取操作,該列表將存儲在內存中。

如果您已經這樣做了,您可以通過(ToHashSet())將您的csv加載到HashSet而不是List中,從而受益。請參閱HashSet vs List Performance