我正在从网站下载数据,网站会在非常大块中向我提供数据。在非常大的块中,我需要单独解析“块”。这些“块”以“(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)块”,但我继续得到内存异常。我也没有运气试图读取预定义块(例如:使用.ReadBytes)。
关于如何处理280MB大型,可能但实际上不是单行文本的任何建议都会很棒!
答案 0 :(得分:1)
这是一种非常低效的阅读文本文件的方式,更不用说大文本了。如果您只需要一次传递,替换或添加单个字符,则应使用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);
}
}
答案 1 :(得分:0)
首先,我不认为您需要将所有文本放在StringBuilder中,因为您甚至不能将部分连接到它。您可以尝试以下方法:
File.ReadAllText(filepath).Replace("\n", "").Replace("<ClinicalData", "\n<ClinicalData");
为什么不尝试使用StreamReader执行此任务?你可以选择一个&#34; chunk&#34;要读取的大小,然后将这些块拆分为(ClinicalData)数据(/ ClinicalData)部分。以下是有关如何执行此操作的详细代码:
char[] buffer = new char[1024];
string remainder = string.Empty;
List<ClientData> list = new List<ClientData>();
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<ClientData> list)
{
string[] parts = value.Split(new string[1] { "</ClientData>" }, 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
}
}
有很多方法可以实现这样的功能,但希望这可以帮助您入门。
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