Подтвердить что ты не робот

Лучше Искать строку во всех файлах с помощью С#

После ссылки на многие блоги и статьи я пришел к следующему коду для поиска строки во всех файлах внутри папки. Он отлично работает в моих тестах.

ВОПРОСЫ

  • Есть ли более быстрый подход для этого (используя С#)?
  • Есть ли какой-либо сценарий, который завершится с этим кодом?

Примечание. Я тестировал очень маленькие файлы. Также очень мало файлов.

CODE

static void Main()
    {
        string sourceFolder = @"C:\Test";
        string searchWord = ".class1";

        List<string> allFiles = new List<string>();
        AddFileNamesToList(sourceFolder, allFiles);
        foreach (string fileName in allFiles)
        {
            string contents = File.ReadAllText(fileName);
            if (contents.Contains(searchWord))
            {
                Console.WriteLine(fileName);
            }
        }

        Console.WriteLine(" ");
        System.Console.ReadKey();
    }

    public static void AddFileNamesToList(string sourceDir, List<string> allFiles)
    {

            string[] fileEntries = Directory.GetFiles(sourceDir);
            foreach (string fileName in fileEntries)
            {
                allFiles.Add(fileName);
            }

            //Recursion    
            string[] subdirectoryEntries = Directory.GetDirectories(sourceDir);
            foreach (string item in subdirectoryEntries)
            {
                // Avoid "reparse points"
                if ((File.GetAttributes(item) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
                {
                    AddFileNamesToList(item, allFiles);
                }
            }

    }

ССЫЛКА

4b9b3361

Ответ 1

Вместо File.ReadAllText() лучше использовать

File.ReadLines(@"C:\file.txt");

Он возвращает IEnumerable (полученный), поэтому вам не нужно будет читать весь файл, если ваша строка будет найдена до того, как будет достигнута последняя строка текстового файла.

Ответ 2

Я написал что-то очень похожее, пару изменений, которые я бы рекомендовал.

  • Используйте Directory.EnumerateDirectories вместо GetDirectories, он немедленно возвращается с IEnumerable, поэтому вам не нужно ждать, пока он закончит чтение все каталоги перед обработкой.
  • Используйте ReadLines вместо ReadAllText, это будет загружать только одну строку за раз в памяти, это будет большой проблемой, если вы нажмите большой файл.
  • Если вы используете новую версию .NET, используйте Parallel.ForEach, это позволит вам одновременно искать несколько файлов.
  • Возможно, вам не удастся открыть файл, вам нужно проверить разрешения на чтение или добавить в манифест, что ваша программа требует административных привилегий (вы все равно должны проверить хотя)

Я создавал двоичный инструмент поиска, вот несколько фрагментов того, что я написал, чтобы дать вам руку

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    Parallel.ForEach(Directory.EnumerateFiles(_folder, _filter, SearchOption.AllDirectories), Search);
}

//_array contains the binary pattern I am searching for.
private void Search(string filePath)
{
    if (Contains(filePath, _array))
    {
        //filePath points at a match.
    }
}

private static bool Contains(string path, byte[] search)
{
    //I am doing ReadAllBytes due to the fact that I am doing a binary search not a text search
    //  There are no "Lines" to seperate out on.
    var file = File.ReadAllBytes(path);
    var result = Parallel.For(0, file.Length - search.Length, (i, loopState) =>
        {
            if (file[i] == search[0])
            {
                byte[] localCache = new byte[search.Length];
                Array.Copy(file, i, localCache, 0, search.Length);
                if (Enumerable.SequenceEqual(localCache, search))
                    loopState.Stop();
            }
        });
    return result.IsCompleted == false;
}

Это использует два вложенных параллельных цикла. Этот проект ужасно неэффективен и может быть значительно улучшен с помощью алгоритма поиска Booyer-Moore, но я не смог найти двоичную реализацию, и я сделал не было времени, когда я написал его изначально для его реализации.

Ответ 3

Основная проблема заключается в том, что вы ищете все файлы в реальном времени для каждого поиска. существует также вероятность конфликтов доступа к файлам, если одновременно ищут 2+ пользователя.

чтобы резко повысить производительность, я бы заранее индексировал файлы, а также их редактировали/сохраняли. сохраните индексированный, используя что-то вроде lucene.net, а затем запросите индекс (снова используя luence.net) и вернуть имена файлов пользователю. поэтому пользователь никогда не запрашивает файлы напрямую.

если вы следуете ссылкам в этой SO Post, у вас может начаться внедрение индексации. Я не следил за ссылками, но это стоит посмотреть.

Просто голова, это будет интенсивный переход от вашего текущего подхода и потребует

  • служба мониторинга/индексации файлов
  • проект пользовательского интерфейса

Ответ 4

Я думаю, что ваш код не сработает с исключением, если вам не хватает permission to open a file.

Сравните его с кодом здесь: http://bgrep.codeplex.com/releases/view/36186

Этот последний код поддерживает

  • поиск регулярных выражений и
  • фильтры для расширений файлов

- вещи, которые вы, вероятно, должны учитывать.

Ответ 5

  • Вместо Contains лучше использовать алгоритм поиска Бойер-Мура.

  • Сбой сценария: файл не имеет разрешения на чтение.