我正在尝试解析具有标题和正文的文本文件。在此文件的标题中,有对主体部分的行号引用。例如:
SECTION_A 256
SECTION_B 344
SECTION_C 556
这意味着,SECTION_A从第256行开始。
将此标题解析为字典的最佳方法是什么,然后在必要时阅读这些部分。
典型的情况是:
数据文件非常大,我绝对不想将所有内容加载到内存中,然后对其进行操作。
我很感激你的建议。我的环境是VS 2008和C#3.5 SP1。
答案 0 :(得分:3)
你可以很容易地做到这一点。
问题分为三个部分。
1)如何查找文件中某一行的起始位置。执行此操作的唯一方法是从文件中读取行,保留一个列表,该列表记录该行文件中的起始位置。 e.g
List lineMap = new List(); lineMap.Add(0); // Line 0 starts at location 0 in the data file (just a dummy entry) lineMap.Add(0); // Line 1 starts at location 0 in the data file using (StreamReader sr = new StreamReader("DataFile.txt")) { String line; int lineNumber = 1; while ((line = sr.ReadLine()) != null) lineMap.Add(sr.BaseStream.Position); }
2)读取索引文件并将其解析为字典。
Dictionary index = new Dictionary(); using (StreamReader sr = new StreamReader("IndexFile.txt")) { String line; while ((line = sr.ReadLine()) != null) { string[] parts = line.Split(' '); // Break the line into the name & line number index.Add(parts[0], Convert.ToInt32(parts[1])); } }
然后在文件中找到一行,请使用:
int lineNumber = index["SECTION_B";]; // Convert section name into the line number long offsetInDataFile = lineMap[lineNumber]; // Convert line number into file offset
然后在DataFile.txt上打开一个新的FileStream,Seek(offsetInDataFile,SeekOrigin.Begin)移动到行的开头,并使用StreamReader(如上所示)从中读取行。
答案 1 :(得分:2)
嗯,显然你可以将名字+行号存储到字典中,但这对你没有任何帮助。
嗯,当然,它会让你知道从哪一行开始读取,但问题是,文件中的哪一行是那行?要知道的唯一方法是从头开始并开始计算。
最好的方法是编写一个解码文本内容的包装器(如果你有编码问题)并且可以给你一个行号到字节位置类型的映射,那么你可以把那个行号,256,看看在字典中知道256行从文件中的位置10000开始,然后从那里开始阅读。
这是一次性处理情况吗?如果没有,您是否考虑将整个文件填充到本地数据库中,如SQLite数据库?这将允许您在行号和其内容之间进行直接映射。当然,该文件甚至会比原始文件大,而且您需要将数据从文本文件复制到数据库,因此无论如何都会产生一些开销。
答案 2 :(得分:0)
一次只读取一行文件并忽略数据,直到找到所需的数据。你不会有任何内存问题,但性能可能不会很好。您可以在后台线程中轻松完成此操作。
答案 3 :(得分:0)
读取文件直到标题的末尾,假设您知道它在哪里。拆分你存储在空格上的字符串,如下所示:
Dictionary<string, int> sectionIndex = new Dictionary<string, int>();
List<string> headers = new List<string>(); // fill these with readline
foreach(string header in headers) {
var s = header.Split(new[]{' '});
sectionIndex.Add(s[0], Int32.Parse(s[1]));
}
找到你想要的字典条目,记住文件中读取的行数,然后循环直到你达到该行号,然后读到你到达下一部分的起始行。我不知道你是否可以保证字典中键的顺序,所以你可能需要当前和下一部分的名字。
请务必进行一些错误检查,以确保您正在阅读的部分不在您正在阅读的部分之前,以及您可以想到的任何其他错误情况。
答案 4 :(得分:0)
您可以逐行读取,直到捕获到所有标题信息并停止(假设所有节指针都在标题中)。您可以使用部分和行号来稍后检索数据。
string dataRow = "";
try
{
TextReader tr = new StreamReader("filename.txt");
while (true)
{
dataRow = tr.ReadLine();
if (dataRow.Substring(1, 8) != "SECTION_")
break;
else
//Parse line for section code and line number and log values
continue;
}
tr.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}