极大的单行文件解析

我正在从一个站点下载数据,该站点以非常大的块为我提供数据。 在非常大的块中,我需要单独解析“块”。 这些“块”以“(ClinicalData)”开头,以“(/ ClinicalData)”结尾。 因此,示例字符串看起来像:

(ClinicalData)(ID="1")(/ClinicalData)(ClinicalData)(ID="2")(/ClinicalData)(ClinicalData)(ID="3")(/ClinicalData)(ClinicalData)(ID="4")(/ClinicalData)(ClinicalData)(ID="5")(/ClinicalData) 

在“理想”情况下,块意味着是单行数据,但有时会出现错误的换行符。 由于我想解析块中的(ClinicalData)块,我想逐行解析数据。 因此,我取文本文件,将其全部读入StringBuilder,删除新行(以防万一),然后插入我自己的换行符,这样我就可以逐行读取。

 StringBuilder dataToWrite = new StringBuilder(File.ReadAllText(filepath), Int32.MaxValue); // Need to clear newline characters just in case they exist. dataToWrite.Replace("\n", ""); // set my own newline characters so the data becomes parse-able by line dataToWrite.Replace("<ClinicalData", "\n<ClinicalData"); // set the data back into a file, which is then used in a StreamReader to parse by lines. File.WriteAllText(filepath, dataToWrite.ToString()); 

这一直很好(虽然可能效率不高,但至少它对我很友好:)),直到我没有遇到一大块数据作为280MB大文件给我。

现在我得到一个带有这个块的System.OutOfMemoryException,我无法找到解决方法。 我相信问题是StringBuilder无法处理280MB的直文? 好吧,我已经尝试了字符串拆分,regex.match拆分,以及各种其他方法将其分解为保证“(ClinicalData)块”,但我继续得到内存exception。我也没有运气试图读取预定义块(例如:使用.ReadBytes)。

关于如何处理280MB大型,可能但实际上不是单行文本的任何建议都会很棒!

这是一种读取文本文件的极其低效的方式,更不用说大文本了。 如果您只需要一次传递,替换或添加单个字符,则应使用StreamReader 。 如果你只需要一个前瞻性角色,你只需要保持一个中间状态,例如:

 enum ReadState { Start, SawOpen } using (var sr = new StreamReader(@"path\to\clinic.txt")) using (var sw = new StreamWriter(@"path\to\output.txt")) { var rs = ReadState.Start; while (true) { var r = sr.Read(); if (r < 0) { if (rs == ReadState.SawOpen) sw.Write('<'); break; } char c = (char) r; if ((c == '\r') || (c == '\n')) continue; if (rs == ReadState.SawOpen) { if (c == 'C') sw.WriteLine(); sw.Write('<'); rs = ReadState.Start; } if (c == '<') { rs = ReadState.SawOpen; continue; } sw.Write(c); } } 

首先,我认为您不需要将所有文本放在StringBuilder中,因为您甚至没有将部分连接到它。 您可以尝试以下方法:

 File.ReadAllText(filepath).Replace("\n", "").Replace(" 

为什么不尝试StreamReader来完成这项任务呢? 您可以选择要读取的“块”大小,然后将这些块拆分为(ClinicalData)数据(/ ClinicalData)部分。 以下是一些有关如何执行此操作的详细代码:

  char[] buffer = new char[1024]; string remainder = string.Empty; List list = new List(); using (StreamReader reader = File.OpenText(@"source.txt")) { while (reader.Read(buffer, 0, 1024) > 0) { remainder = Parse(remainder + new string(buffer), list); } } 

使用以下方法:

 string Parse(string value, List list) { string[] parts = value.Split(new string[1] { "" }, StringSplitOptions.None); for (int i = 0; i < parts.Length - 1; i++) list.Add(new ClientData(parts[i])); return parts[parts.Length - 1]; } 

然而,你实现了ClientData类:

 class ClientData { public ClientData(string value) { // fill in however you are already parsing out ID, and other info } } 

有很多方法可以实现这样的function,但希望这可以帮助您入门。

StreamReader的ReadLine()方法只是您可以从文件中读取文本的众多方法之一。 您可以读入具有指定长度的缓冲区,然后解析出ClinicalData标记。 如果你愿意,我可以提供一个例子。 http://msdn.microsoft.com/en-us/library/9kstw824%28v=vs.110%29.aspx

或者,如果您正在读取XML文件,则XmlReader是另一种选择。 http://msdn.microsoft.com/en-us/library/system.xml.xmlreader%28v=vs.110%29.aspx