1

我正在尝试解析具有标题和正文的文本文件。在该文件的标题中,有对正文部分的行号引用。例如:

SECTION_A 256
SECTION_B 344
SECTION_C 556

这意味着 SECTION_A 从第 256 行开始。

将这个标题解析成字典然后在必要时阅读这些部分的最佳方法是什么。

典型的场景是:

  1. 解析标题和只读部分 SECTION_B
  2. 解析标题并阅读每个部分的第一段。

数据文件很大,我绝对不想全部加载到内存中再操作。

我会很感激你的建议。我的环境是 VS 2008 和 C# 3.5 SP1。

4

5 回答 5

3

你可以很容易地做到这一点。

问题分为三个部分。

1)如何找到文件中一行的开始位置。做到这一点的唯一方法是从文件中读取行,保留一个记录该行在文件中的开始位置的列表。例如

列表 lineMap = new List();
lineMap.Add(0); // 第 0 行从数据文件中的位置 0 开始(只是一个虚拟条目)
lineMap.Add(0); // 第 1 行从数据文件中的位置 0 开始

使用 (StreamReader sr = new StreamReader("DataFile.txt"))
{
    字符串线;
    int lineNumber = 1;
    而 ((line = sr.ReadLine()) != null)
        lineMap.Add(sr.BaseStream.Position);
}

2)读取索引文件并将其解析为字典。

字典索引 = new Dictionary();

使用 (StreamReader sr = new StreamReader("IndexFile.txt"))
{
    字符串线;
    而 ((line = sr.ReadLine()) != null)
    {
        string[] 部分 = line.Split(' '); // 将行分成名称和行号
        index.Add(parts[0], Convert.ToInt32(parts[1]));
    }
}

然后要在文件中查找一行,请使用:

int lineNumber = index["SECTION_B";]; // 将节名转换为行号
长 offsetInDataFile = lineMap[lineNumber]; // 将行号转换为文件偏移量

然后在 DataFile.txt 上打开一个新的 FileStream,Seek(offsetInDataFile, SeekOrigin.Begin) 移动到行的开头,并使用 StreamReader(如上)从中读取行。

于 2009-05-06T19:54:57.373 回答
2

好吧,显然您可以将名称 + 行号存储到字典中,但这对您没有任何好处。

好吧,当然,它会让您知道从哪一行开始读取,但问题是,该行在文件中的什么位置?唯一知道的方法是从头开始并开始计数。

最好的方法是编写一个包装器来解码文本内容(如果你有编码问题)并且可以给你一个行号到字节位置类型的映射,那么你可以取那个行号 256,然后在字典中查找要知道第 256 行从文件中的位置 10000 开始,然后从那里开始读取。

这是一次性处理的情况吗?如果没有,您是否考虑将整个文件填充到本地数据库中,例如 SQLite 数据库?这将允许您在行号与其内容之间进行直接映射。当然,该文件会比您的原始文件更大,并且您需要将数据从文本文件复制到数据库,因此无论哪种方式都有一些开销。

于 2009-05-06T19:22:35.767 回答
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]));
}

找到您想要的字典条目,计算文件中读取的行数,然后循环直到您到达该行号,然后阅读直到您到达下一节的起始行。我不知道您是否可以保证字典中键的顺序,因此您可能需要当前和下一个部分的名称。

请务必进行一些错误检查,以确保您正在阅读的部分不在您正在阅读的部分之前,以及您能想到的任何其他错误情况。

于 2009-05-06T19:36:40.320 回答
0

只需一次读取一行文件并忽略数据,直到找到所需的数据。您不会有任何内存问题,但性能可能不会很好。不过,您可以在后台线程中轻松完成此操作。

于 2009-05-06T19:27:32.417 回答
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);
}
于 2009-05-06T19:50:06.730 回答