Soru C # [kapalı] kullanarak tüm dosyalarda bir dize için Daha İyi Arama


Birçok blog ve makaleye atıfta bulunduktan sonra, bir klasördeki tüm dosyalarda bir dize aramak için aşağıdaki kodda ulaştım. Testlerimde gayet iyi çalışıyor.

SORULARI

  1. Bunun için daha hızlı bir yaklaşım var mı (C # kullanarak)?
  2. Bu kod ile başarısız olacak herhangi bir senaryo var mı?

Not: Çok küçük dosyalarla test ettim. Ayrıca çok az sayıda dosya.

KOD

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

    }

REFERANS

  1. Bir dosyanın bir dizgi içerip içermediğini kontrol etmek için StreamReader'ı kullanma
  2. Bir dizeyi iki ölçütle bölme
  3. C # bir yoldaki klasör bağlantılarını algılar
  4. Sembolik Bağlantıları, Bağlantı Noktalarını, Montaj Noktalarını ve Sabit Bağlantıları Algıla
  5. Yeniden ayırma noktaları olan FolderBrowserDialog SelectedPath
  6. C # - Yüksek Kaliteli Bayt Array Görüntülerin Dönüştürülmesi

28
2017-12-21 16:15


Menşei


Bu CodeReview sitesine daha uygun olabilir: codereview.stackexchange.com - Simon Martin
Kullanılabilir RAM'inizden daha büyük bir dosyayı test ettiniz mi ve takas mı yaptınız? - Dark Falcon
@DarkFalcon Çok küçük dosyalarla test ettim. Ayrıca çok az sayıda dosya. - Lijo
Eh, en azından çok büyük dosyaları ile yavaş (veya işe yaramaz). Üstelik çok sayıda dosya varsa, o da asar (aramaya başlamadan önce tüm listeyi oluşturduğunuz için). - Adriano Repetti
EnumerateFiles (msdn.microsoft.com/en-us/library/...) adım adım tarama ve (çok büyük metin dosyaları işlemek zorundaysanız) daha iyi bir arama algoritması da (en.wikipedia.org/wiki/..., Örneğin). - Adriano Repetti


Cevaplar:


File.ReadAllText () yerine daha iyi kullanmak

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

Döner IEnumerable (verilmiş) bu nedenle, metin dosyanızın son satırına ulaşmadan dizeniniz bulunursa, tüm dosyayı okumak zorunda kalmazsınız


26
2017-12-21 16:20





Çok benzer bir şey yazdım, önereceğim birkaç değişiklik.

  1. kullanım Directory.EnumerateDirectories GetDirectories yerine, hemen bir IEnumerable ile döner, bu nedenle işlemeden önce tüm dizinleri okumayı bitirmesini beklemenize gerek yoktur.
  2. kullanım readlines ReadAllText yerine, bu sadece bir satırda bellekte bir kez yükleyecektir, büyük bir dosyaya vurursanız, bu büyük bir anlaşma olacaktır.
  3. .NET'in yeterince yeni bir sürümünü kullanıyorsanız Parallel.ForEachBu, aynı anda birden çok dosya aramanıza izin verecektir.
  4. Dosyayı açamayabilirsiniz, okuma izinlerini kontrol etmeniz veya tezahürüne ekle Programınızın yönetici ayrıcalıkları gerektirdiğini (yine de kontrol etmelisiniz)

Bir ikili arama aracı oluşturuyordum, işte size bir el vermek için yazdıklarımın bazı parçacıkları

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

Bu iki yuvalanmış paralel döngü kullanır. Bu tasarım aşırı derecede verimsizdir ve Booyer-Moore arama algoritması ama ikili bir uygulama bulamadım ve orijinal olarak kendimi uygulamak için yazdığım zamana sahip değildim.


9
2017-12-21 16:36





Buradaki asıl sorun, tüm dosyaları her arama için gerçek zamanlı olarak aramanızdır. Ayrıca 2+ kullanıcı aynı anda arama yapıyorsa dosya erişim çakışmaları olasılığı vardır.

Performansı dramatik bir şekilde geliştirmek için dosyaları önceden işaretleyeceğim ve düzenlendikçe / kaydedildiklerinde. endeksli gibi bir şey kullanarak lucene.net ve sonra indeksi sorgulayın (tekrar kullanarak luence.net) ve dosya adlarını kullanıcıya döndür. Böylece kullanıcı dosyaları doğrudan sormaz.

Bu linkleri takip ederseniz SO Post İndekslemeyi uygulamaya başlamak için bir başlangıç ​​olabilir. Linkleri takip etmedim, ama bir göz atmaya değer.

Sadece bir kafa, bu mevcut yaklaşımından yoğun bir değişim olacak ve gerekecek

  1. dosyaları izlemek / indekslemek için bir servis
  2. UI projesi

3
2017-12-21 16:30



Çoğu zaman gerçek zamanlı bir dosya araması tam olarak istediğim şeydir. Bir programcı olarak, aradığım birçok şey bilinen uzantılara sahip küçük metin dosyalarında. Çalışırken, bu büyük dizinlerin RAM'le uğraşmasını ve diskimdeki çiğnemeyi istemiyorum. Diskim bir sebepten dolayı hızlı. - Brannon


Eğer eksikliğiniz varsa kodunuzun bir istisna ile başarısız olacağını düşünüyorum. permission to open a file.

Buradaki kodla karşılaştırın: http://bgrep.codeplex.com/releases/view/36186 

Bu ikinci kod destekliyor

  1. düzenli ifade araması ve
  2. dosya uzantıları için filtreler

- Muhtemelen düşünmeniz gereken şeyler.


1
2017-12-21 16:22



Tipik olarak, dosyalarda yazarken, arama dizesinde birkaç joker karaktere atabilirsiniz. Yukarıdaki kod, sabit kodlanmış bir ".class1" arıyor. Amaç buysa, sorun yok. Ancak, bu, parametreleştirmek istediğiniz türden bir şeydir - bir kişi nasıl kodlanmış girişlerle süslü kodu yeniden kullanabilir? Düzenli ifadeler bunu bir adım daha ileriye götürür: Aletin gücünü arttırırlar. Çok sayıda övgü var ve web'de Düzenli İfadeler için yardımcı oluyor. Konsepte aşina değilseniz, bakın. - Brannon


  1. Yerine Contains Daha iyi algoritma Boyer-Moore arama kullanın.

  2. Hata senaryosu: dosya izin okumadı.


1
2017-12-21 16:34



IndexOf'u kullanarak StringComparison.Ordnal veya OrdnalIgnoreCase olduğu daha fazla performans Boyer-Moore'dan. ve Contains aramalar IndexOf (değer, StringComparison.Ordinal) - Scott Chamberlain