从大文件中以非升序读取多行

Tiz*_*izz 2 c# file streamreader filereader

我有一个非常大的文本文件,超过1GB,并且有一个代表行号的整数列表,需要生成另一个文件,其中包含新文件中原始文件行号的文本。

原始大文件示例:

ogfile line 1
some text here
another line
blah blah
Run Code Online (Sandbox Code Playgroud)

因此,当我得到“ 2,4,4,1”的列表时,输出文件应为:

some text here
blah blah
blah blah
ogfile line 1
Run Code Online (Sandbox Code Playgroud)

我试过了 string lineString = File.ReadLines(filename).Skip(lineNumList[i]-1).Take(1).First();

但这要花很长时间,因为必须读取文件,跳到有问题的行,然后在下一次重新读取...而且我们正在谈论1GB文件中的数百万行,而我List<int>是成千上万的行号。

是否有更好/更快的方法来读取单行,或者让读者跳到特定的行号而不逐行“跳过”?

Eri*_*ert 5

这里的高级位是:您正在尝试使用文本文件解决数据库问题。数据库旨在解决大数据问题;您已经发现,文本文件在随机访问时非常糟糕。使用数据库,而不是文本文件

如果您不喜欢使用文本文件,那么您所要做的就是利用您所了解的有关可能的问题参数的知识。例如,如果您知道(暗示)有〜1M行,每行为〜1KB,并且要提取的行集为总行的〜0.1%,那么您可以想出一个有效的解决方案,例如这个:

  • 设置一个包含要读取的行号的集合。该集合必须快速检查成员资格。
  • 制作一个从行号映射到行内容的字典。必须快速按键查找和快速添加新的键/值对。
  • 一次读取文件的每一行;如果行号在集合中,则将内容添加到字典中。
  • 现在迭代行号列表并映射字典内容;现在我们有了一个字符串序列。
  • 将该序列转储到目标文件。

我们有五个操作,所以希望它大约有五行代码。

void DoIt(string pathIn, IEnumerable<int> lineNumbers, string pathOut)
{
  var lines = new HashSet<int>(lineNumbers);
  var dict = File.ReadLines(pathIn)
    .Select((lineText, index) => new KeyValuePair<int, string>(index, lineText))
    .Where(p => lines.Contains(p.Key))
    .ToDictionary(p => p.Key, p => p.Value);
  File.WriteAllLines(pathOut, lineNumbers.Select(i => dict[i]));
}
Run Code Online (Sandbox Code Playgroud)

好,六点钟就知道了。非常好。


注意,我利用了所有这些假设。如果违反了假设,那么这将不再是一个好的解决方案。特别是,我们假设字典将比输入文件的大小小。如果那不是真的,那么您将需要一种更复杂的技术来提高效率。

相反,我们可以提高效率吗? 是的,只要我们知道有关可能输入的事实。例如,假设我们知道同一文件将被迭代几次,但是行号集不同,但是这些集可能重叠。在那种情况下,我们可以重用字典而不是重建它们。也就是说,假设先前的操作已为第Dictionary<int, string>X行,第10、20、30、40行和文件X 留下了计算值。如果随后有对X文件的第(30、20、10)行的请求,我们已经有了字典在记忆中。

我想在这个答案中得到的关键是,您必须了解一些有关输入的知识,以便构建有效的解决方案。您对输入的限制越多,构建的解决方案就越有效。利用您所拥有的有关问题域的所有知识。