31

多くのブログや記事を参照した後、フォルダー内のすべてのファイルで文字列を検索する次のコードにたどり着きました。私のテストでは問題なく動作しています。

質問

  1. これに対するより高速なアプローチはありますか (C# を使用)?
  2. このコードで失敗するシナリオはありますか?

注: 非常に小さなファイルでテストしました。また、ファイル数が非常に少ない。

コード

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);
                }
            }

    }

参照

  1. StreamReader を使用してファイルに文字列が含まれているかどうかを確認する
  2. 2 つの条件で文字列を分割する
  3. C#はパス内のフォルダージャンクションを検出します
  4. シンボリック リンク、ジャンクション ポイント、マウント ポイント、ハード リンクの検出
  5. FolderBrowserDialog SelectedPath と再解析ポイント
  6. C# - 画像の高品質バイト配列変換
4

5 に答える 5

30

File.ReadAllText() の代わりに使用することをお勧めします

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

テキストIEnumerableファイルの最終行に到達する前に文字列が見つかった場合、ファイル全体を読み取る必要はありません。

于 2012-12-21T16:20:38.547 に答える
11

私は非常によく似たものを書きましたが、いくつかの変更をお勧めします。

  1. GetDirectories の代わりにDirectory.EnumerateDirectoriesを使用します。IEnumerable ですぐに返されるため、処理前にすべてのディレクトリの読み取りが完了するのを待つ必要はありません。
  2. ReadAllText の代わりにReadLinesを使用します。これは一度に 1 行しかメモリにロードしません。大きなファイルにヒットした場合、これは大変なことになります。
  3. 十分に新しいバージョンの .NET を使用している場合は、Parallel.ForEachを使用すると、一度に複数のファイルを検索できます。
  4. ファイルを開くことができない場合があります。読み取り権限を確認するか、プログラムに管理者権限が必要であることをマニフェストに追加する必要があります (それでも確認する必要があります)。

私はバイナリ検索ツールを作成していました。ここに、私が書いたものの一部を示します。

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;
}

これは、ネストされた 2 つの並列ループを使用します。この設計は非常に非効率的で、 Booyer-Moore 検索アルゴリズムを使用することで大幅に改善される可能性がありますが、バイナリ実装を見つけることができず、最初に書いたときに自分で実装する時間がありませんでした。

于 2012-12-21T16:36:45.843 に答える
3

ここでの主な問題は、すべての検索ですべてのファイルをリアルタイムで検索していることです。2人以上のユーザーが同時に検索している場合、ファイルアクセスの競合が発生する可能性もあります。

パフォーマンスを大幅に向上させるために、事前にファイルのインデックスを作成し、編集/保存します。lucene.netのようなものを使用してインデックスを保存してから、インデックスをクエリし(ここでもluence.netを使用)、ファイル名をユーザーに返します。したがって、ユーザーがファイルを直接照会することはありません。

このSO投稿のリンクをたどると、インデックス作成の実装に有利なスタートを切ることができます。リンクをたどりませんでしたが、一見の価値があります。

ただ注意してください、これはあなたの現在のアプローチからの激しいシフトであり、

  1. ファイルを監視/インデックス付けするサービス
  2. UIプロジェクト
于 2012-12-21T16:30:03.837 に答える
1

が不足している場合、例外を除いてコードは失敗すると思いますpermission to open a file

ここのコードと比較してください:http://bgrep.codeplex.com/releases/view/36186

後者のコードは

  1. 正規表現検索と
  2. ファイル拡張子のフィルター

-おそらく考慮すべきこと。

于 2012-12-21T16:22:56.690 に答える
1
  1. 代わりに、Containsボイヤー・ムーア検索アルゴリズムを使用することをお勧めします。

  2. 失敗のシナリオ: ファイルには読み取り権限がありません。

于 2012-12-21T16:34:47.357 に答える