Поиск нескольких строк в нескольких файлах - PullRequest
6 голосов
/ 21 октября 2010

У меня есть текстовый файл, содержащий 21000 строк (по одной строке) и 500 МБ других текстовых файлов (исходные коды maily).Для каждой строки мне нужно определить, содержится ли она в каком-либо из этих файлов.Я написал программу, которая выполняет эту работу, но ее производительность ужасна (она сделает это через пару дней, мне нужно выполнить работу максимум за 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
}

б) Лучше сканировать одну строку за строкой

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) Есть ли какое-нибудь программное обеспечение, которое может это сделать, чтобы мне не приходилось писать свой собственный код?

Ответы [ 5 ]

6 голосов
/ 21 октября 2010

Если вы просто хотите узнать, найдена строка или не найдена, и вам не нужно выполнять какую-либо дальнейшую обработку, тогда я бы посоветовал вам просто использовать grep.Grep очень быстр и предназначен именно для такого рода проблем.

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

должно сработать.Я уверен, что где-то есть реализация Windows.В худшем случае Cygwin получит его.

РЕДАКТИРОВАТЬ: Это отвечает на вопрос d)

3 голосов
/ 21 октября 2010

Вы хотите минимизировать файловый ввод / вывод, поэтому ваша первая идея очень плоха, потому что вы открываете «другие» файлы до 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) ....
    }

}

Часть грубой силы может быть улучшена, но я думаю, вы найдете ее приемлемой.

2 голосов
/ 21 октября 2010

Должен ли поиск выполняться в реальном времени по текущим 500 МБ текста? Причина, по которой я спрашиваю, заключается в том, что вы можете построить поисковый индекс по текстовым файлам и выполнить поиск. Это было бы намного быстрее ... Взгляните на Lucene

Lucene.Net

C # и Lucene для индексации и поиска

2 голосов
/ 21 октября 2010
  1. В обоих случаях a) и b) эффективен второй вариант
  2. Потоки могут не улучшить производительность, потому что каждый поток будет читать файл с вашего диска, поэтому ваш диск станет узким местом.
  3. извините, я понятия не имею о з / ш для вашей цели

фрагмент темы

      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

Общие рекомендации по вводу / выводу

Ниже приведены некоторые основные рекомендации по снижению активности ввода-вывода вашей программы и, следовательно, повышению ее производительности. Как и во всех рекомендациях, важно измерить производительность оптимизируемого кода до и после оптимизации, чтобы убедиться, что он действительно становится быстрее.

  1. Минимизировать количество файлов выполняемые вами операции
  2. Группировка нескольких небольших операций ввода / вывода в один большой перевод. Один запись восьми страниц быстрее, чем восемь отдельных одностраничных записей, в первую очередь потому, что это позволяет жесткий диск для записи данных за один проход по поверхности диска. Для большего информация
  3. Выполнять последовательные чтения вместо искать и читать небольшие блоки данные. Ядро прозрачно кластерные операции ввода / вывода, что делает последовательное чтение намного быстрее.
  4. Избегайте пропускать вперед в пустом файл перед записью данных. Система должны записать нули в промежуточное пространство, чтобы заполнить пробел. Для получения дополнительной информации см. Чтение как правило, дешевле, чем писать данные.
  5. Отложить любые операции ввода-вывода до указать, что ваше приложение на самом деле нужны данные.
  6. Используйте систему настроек для захватывать только пользовательские настройки (например, как положения окна и вид настройки), а не данные, которые могут быть недорого пересчитано.
  7. Не предполагайте, что данные кэшируются в файле в памяти ускорит ваш приложение. Хранение данных файла в память улучшает скорость до тех пор память выгружается на диск, в в какой момент вы платите цену доступ к диску еще раз. Стремитесь найти подходящий баланс между чтением с диска и кеширование в памяти
2 голосов
/ 21 октября 2010

Возможно, вы захотите взглянуть на Windows Search SDK здесь

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

...