关于c#:从多个文件一次读取特定行的最快方法

Quickest way to Read Specific Line from Multiple Files one Line at a time

我有一个基于文本的数据库,该数据库代表按时间戳排序的日志。为了进行测试,我的数据库大约有10,000行,但是这个数目可能更大。其格式为:

primary_key, source_file, line_num
1, cpu.txt, 2
2, ram.txt, 3
3, cpu.txt, 3

我查询数据库,并在读取结果时想将实际数据添加到可以显示的字符串中。上面示例中的实际数据是cpu.txt中第2行的内容,其次是ram.txt中第3行的内容,依此类推。该行内容可能很长。

重要说明是每个文件的行号都是有序的。也就是说,下次我在数据库中遇到cpu.txt条目时,它将以行4作为行号。但是,只有在ram.txt,harddrive.txt,graphics.txt等中的数千个其他条目之后,我才可能看到cpu.txt条目。

我已经考虑过按照以下代码使用某些东西:

1
2
3
4
5
6
7
8
9
StringBuilder odbcResults = new StringBuilder();
OdbcDataReader dbReader = com.ExecuteReader();  // query database
while (dbReader.Read())
{
   string fileName = dbReader[1].ToString(); // source file
   int fileLineNum = int.Parse(dbReader[2].ToString());  // line number in source file

   odbcResults.Append(File.ReadLines(fileName).Skip(fileLineNum).First());
}

但是,File.ReadLines()不想在每次迭代后都丢弃其TextReader吗?不是很有效吗?

我也有这个想法,为需要在Dict中读取的每个文件保留一个StreamReader:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Dictionary<string, StreamReader> fileReaders = new Dictionary<string, StreamReader>();
StringBuilder odbcResults = new StringBuilder();
OdbcDataReader dbReader = com.ExecuteReader();
while (dbReader.Read())
{
   string fileName = dbReader[1].ToString(); // source file
   int fileLineNum = int.Parse(dbReader[2].ToString());  // line number in source file

   if (!fileReaders.ContainsKey(fileName))
   {
      fileReaders.Add(fileName, new StreamReader(fileName));
   }

   StreamReader fileReader = fileReaders[fileName];
   // don't have to worry about positioning? Lines consumed consecutively
   odbcResults.Append(fileReader.ReadLine());
}
// can't forget to properly Close() and Dispose() of all fileReaders

您是否同意上述任何示例,或者有更好的方法吗?
对于第二个示例,我假设StreamReader会记住它的最后位置-我认为这将保存在BaseStream中。

我已经阅读了如何读取文本文件中的指定行?,在特定行读取文本文件,StreamReader并查找(第一个答案提供了到具有定位功能的自定义StreamReader类的链接,但我只知道行号我需要发言,而不是抵消),但不要以为他们会具体回答我的问题。


如果可以保证行引用在文件中严格按顺序排列(即,在要求第n行之后总是要求第n + 1行),那么选择保留StreamReader实例字典的选择看起来不错。理念。

如果您可能要求第n行,然后是第n + x行(其中x是某个正数> = 1),那么我会将StreamReader包裹在一个跟踪当前行号并具有方法< x2>,它将返回请求的行号。假设请求的行号大于当前行号(不允许向后读取)。

您不必担心定位。这是为您处理的,因为您要按顺序阅读。


听起来您好像希望将用户选择的所有内容都存储在内存中(以便在文本框中显示),因此这对于任何可行的操作都是一个自然界限。我建议采用以下方法:

  • 从数据库中读取所有匹配的元数据(即在用户指定的时间范围内)到列表中。保留一组我们需要阅读的文件。
  • 创建一个与列表大小相同的新数组-这将保存最终数据
  • 一次浏览一个所需文件:

    • 打开文件,记住我们在第0行
    • 遍历元数据列表。对于与我们当前打开的文件匹配的每个条目,向前读到右行,并填充与我们正在查看的列表条目相对应的最终数据数组元素。我们应该只需要向前阅读,因为我们仍然按照时间戳顺序进行。
    • 关闭档案

此时,"最终数据数组"应完全填充。您一次只需要打开一个文件,就不需要读取整个文件。我认为这比拥有打开文件的字典更简单-除了其他功能之外,这意味着您可以为每个文件使用using语句,而不必手动处理所有关闭操作。

这确实意味着一次将所有数据库元数据条目都存储在内存中,但是大概每个元数据条目都比最后要在内存中具有的结果数据要小,以便向用户显示结果。

即使您要遍历数据库元数据条目多次,也都将在内存中进行。与文件系统或数据库的IO相比,它应该无关紧要。

一种替代方法是在读取元数据条目时按文件名对其进行分组,并将索引保??留为元数据条目的一部分。