【问题标题】:Searching for multiple strings in multiple files在多个文件中搜索多个字符串
【发布时间】:2011-04-28 13:59:49
【问题描述】:

我有一个包含 21000 个字符串(每行一行)和 500 MB 其他文本文件(主要是源代码)的文本文件。对于每个字符串,我需要确定它是否包含在任何这些文件中。我编写的程序可以完成这项工作,但它的性能很糟糕(它会在几天内完成,我需要在最多 5-6 小时内完成这项工作)。
我正在使用 C#、Visual Studio 2010 编写

我有几个关于我的问题的问题:
a) 哪种方法更好?

foreach(string s in StringsToSearch)
{
    //scan all files and break when string is found
}

foreach(string f in Files)
{
    //search that file for each string that is not already found
}

b) 逐行扫描一个文件是否更好

StreamReader r = new StreamReader(file);
while(!r.EndOfStream)
{
    string s = r.ReadLine();
    //... if(s.Contains(xxx));
}

StreamReader r = new StreamReader(file);
string s = r.ReadToEnd();
//if(s.Contains(xxx));

c) 线程会提高性能吗?如何做到这一点?
d) 有没有什么软件可以做到这一点,这样我就不用自己写代码了?

【问题讨论】:

  • 程序一定要写吗? windows 内置了 findstr。您可以使用 for 循环来并行搜索这些其他文件
  • 绝对不是一个正确/完整的答案,但不要为每个字符串加载所有(500MB!)文件。一旦你有(部分)文件在内存中,然后执行所有操作。
  • 我要一个一个地加载整个文件,而不是一次加载 500 MB 的文件。
  • 你在什么操作系统上,如果你在 Win7 上,你可以在文件中自动搜索,而且速度非常快。

标签: c# string visual-studio-2010 file search


【解决方案1】:

如果您只是想知道是否找到了字符串,并且不需要做任何进一步的处理,那么我建议您使用 grep。 Grep 速度极快,专为此类问题而设计。

grep -f strings-file other-files...

应该可以解决问题。我确信某处有一个 Windows 实现。在最坏的情况下,Cygwin 会拥有它。

编辑:这回答了问题 d)

【讨论】:

  • 是的,尽管有 [C#] 标签,这可能是最好的方法。
  • 我不熟悉 grep 以及它是如何工作的,所以对于如何使用它可能没什么帮助?
  • Grep 是 *nix 系统中非常常见的工具。那里有很多文档,所以一定会有一个很好的教程。建议的命令在任何“其他文件”中查找在“字符串文件”中找到的所有字符串,并打印出“其他文件”中的所有匹配行。有很多选项可以将输出更改为您需要的内容。
【解决方案2】:

您希望最小化文件 I/O,因此您的第一个想法非常糟糕,因为您将打开“其他”文件多达 21.000 次。你想使用基于第二个(a1)的东西。当其他文件不是太大时,使用 readAllText 将它们加载到内存中一次。

List<string> keys = ...;    // load all strings

foreach(string f in Files)
{
    //search for each string that is not already found
    string text = System.IO.File.ReadAllText(f);  //easy version of ReadToEnd


    // brute force
    foreach(string key in keyes)
    {
        if (text.IndexOf(key) >= 0) ....
    }

}

蛮力部分可以改进,但我认为你会发现它可以接受。

【讨论】:

  • if(text.IndexOf(key)>=0) 比 if(text.Contains(key)) 快吗?
  • @Ichi:不,我希望它们同样快。
【解决方案3】:

您可能想在此处查看 Windows Search SDK

http://msdn.microsoft.com/en-us/library/aa965362%28VS.85%29.aspx

【讨论】:

    【解决方案4】:

    是否必须对当前 500 MB 的文本进行实时搜索? 我问的原因是因为您可以在文本文件上建立搜索索引并执行搜索。会快很多……看看Lucene

    Lucene.Net

    C# and Lucene to index and search

    【讨论】:

    • 不需要实时搜索。这是一次任务。做并忘记它:P
    • 然后用Lucene(我没用过Windows Search SDK)建立一个完整的搜索索引并对其进行查找...我之前用过Lucene...速度很快!
    【解决方案5】:
    1. 在 a) 和 b) 中,第二个选项是有效的
    2. 线程可能不会提高性能,因为每个线程都会从您的磁盘读取文件,因此您的磁盘将成为瓶颈。
    3. 对不起,我不知道你的目的是什么

    线程sn-p

          foreach (FileInfo file in FileList)
          {
             Thread t  = new Thread(new ParameterizedThreadStart(ProcessFileData));
             t.Start(file.FullName);  
           }//where processFileData is the method that process the files
    

    一般 I/O 指南

    以下是减少程序的 I/O 活动从而提高其性能的一些基本建议。与所有建议一样,重要的是要衡量优化前后代码的性能,以确保它实际上变得更快。

    1. 最小化文件数 您执行的操作
    2. 对多个小型 I/O 传输进行分组 汇入一笔大转帐。一个 写八页比 八个单独的单页写入, 主要是因为它允许硬 磁盘一次写入数据 在磁盘表面。更多 信息,
    3. 执行顺序读取而不是 寻找和阅读小块 数据。内核透明 集群 I/O 操作,这使得 顺序读取速度更快。
    4. 避免在空白处跳过 写入数据之前的文件。系统 必须将零写入 插入空间以填补空白。 有关更多信息,请参阅阅读 通常比写作便宜 数据。
    5. 将任何 I/O 操作推迟到 指出您的应用程序实际上 需要数据。
    6. 使用首选项系统 仅捕获用户偏好(例如 作为窗口位置和视图 设置),而不是可能的数据 廉价地重新计算。
    7. 不要假设缓存文件数据 在内存中会加快你的 应用。将文件数据存储在 内存提高速度,直到那个 内存被换出到磁盘,在 你为哪一点付出代价 再次访问磁盘。 努力寻找合适的 从磁盘读取之间的平衡 并缓存在内存中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 2012-05-17
      • 2014-10-30
      • 2011-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多