Wir befinden uns seit dem 24. Februar 2022 im Kriegszustand mit Russland. Um der Ukraine so schnell wie möglich zum Sieg zu verhelfen, ignorieren Sie bitte alle russischen Produkte, Unternehmen, Projekte ... alles.
Sie können den Streitkräften der Ukraine auch hier helfen: https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi
Wir werden unser Vaterland von den russischen Eindringlingen befreien und Europa vor dem aggressiven und unmenschlichen russischen Regime retten. Ich verspreche es.
Wenn Sie mich persönlich unterstützen möchten, können Sie dies hier tun: https://ko-fi.com/VladPVS
Die Multithreading-.NET-Bibliothek, die die Möglichkeit bietet, Dateien oder Verzeichnisse mithilfe verschiedener Suchkriterien schnell zu finden.
Die .NET Core-Version ist hier verfügbar.
Das MIF-Dateisuchtool basiert auf dieser Bibliothek. Sie können es ausprobieren, wenn Sie sofort die Arbeitsgeschwindigkeit abschätzen möchten.
using FastSearchLibrary;
4.5.1
fest, wenn Sie Version 1.1.6.1 der Bibliothek verwenden, oder 4.6.2
wenn Sie mindestens Version 1.1.7.2 verwenden: Projekt -> Eigenschaften -> Zielframework Die nächsten Klassen bieten Suchfunktionen:
FileSearcher
und DirectorySearcher
enthalten statische Methoden, die die Suche nach unterschiedlichen Kriterien ermöglichen. Diese Methoden geben nur dann ein Ergebnis zurück, wenn sie die Ausführung vollständig abgeschlossen haben.string folder
– Suchverzeichnis startenstring pattern
– die Suchzeichenfolge, die mit den Namen der Dateien im Pfad abgeglichen werden soll. Dieser Parameter kann eine Kombination aus gültigem Literalpfad und Platzhalterzeichen (* und ?) enthalten, unterstützt jedoch keine regulären Ausdrücke.Beispiele:
List < FileInfo > files = FileSearcher . GetFiles ( @"C:Users" , " *.txt " ) ;
Findet alle *.txt
Dateien in C:Users
mit einer Thread-Methode.
List < FileInfo > files = FileSearcher . GetFilesFast ( @"C:Users" , " *SomePattern*.txt " ) ;
Findet mithilfe mehrerer Threads im Thread-Pool alle Dateien, die dem entsprechenden Muster entsprechen.
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"C:" , " a?.txt " ) ;
Findet alle Dateien, die dem entsprechenden Muster entsprechen, indem mehrere Threads im Thread-Pool als asynchroner Vorgang verwendet werden.
string folder
– Suchverzeichnis startenFunc<FileInfo, bool> isValid
– Delegat, der den Algorithmus der Dateiauswahl bestimmt.Beispiele:
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"D:" , ( f ) =>
{
return ( f . Name . Contains ( " Pattern " ) || f . Name . Contains ( " Pattern2 " ) ) && f . LastAccessTime >= new DateTime ( 2018 , 3 , 1 ) && f . Length > 1073741824 ;
} ) ;
Findet alle Dateien, die den entsprechenden Bedingungen entsprechen, indem mehrere Threads im Thread-Pool als asynchroner Vorgang verwendet werden.
Sie können auch reguläre Ausdrücke verwenden:
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"D:" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".*Imagine[s_-]Dragons.*.mp3$" ) ;
} ) ;
Findet alle Dateien, die dem entsprechenden regulären Ausdruck entsprechen, mithilfe mehrerer Threads im Thread-Pool als asynchrone Operation.
Wenn Sie eine komplizierte Suche mit Echtzeit-Ergebnisabfrage durchführen möchten, sollten Sie eine Instanz der FileSearcher
-Klasse verwenden, die über verschiedene Konstruktorüberladungen verfügt. FileSearcher
-Klasse enthält die nächsten Ereignisse:
event EventHandler<FileEventArgs> FilesFound
– wird ausgelöst, wenn der nächste Teil der Dateien gefunden wird. Das Ereignis enthält List<FileInfo> Files { get; }
-Eigenschaft, die eine Liste der gefundenen Dateien enthält.event EventHandler<SearchCompleted> SearchCompleted
– wird ausgelöst, wenn der Suchvorgang abgeschlossen oder gestoppt ist. Das Ereignis enthält bool IsCanceled { get; }
-Eigenschaft, die einen Wert enthält, der definiert, ob der Suchvorgang durch Aufrufen StopSearch()
Methode gestoppt wird. Um die Möglichkeit zu erhalten, den Suchvorgang zu stoppen, muss ein Konstruktor verwendet werden, der den Parameter CancellationTokenSource akzeptiert.Beispiel:
class Searcher
{
private static object locker = new object ( ) ; // locker object
private FileSearcher searcher ;
private List < FileInfo > files ;
public Searcher ( )
{
files = new List < FileInfo > ( ) ; // create list that will contain search result
}
public void StartSearch ( )
{
CancellationTokenSource tokenSource = new CancellationTokenSource ( ) ;
// create tokenSource to get stop search process possibility
searcher = new FileSearcher ( @"C:" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".*[iI]magine[s_-][dD]ragons.*.mp3$" ) ;
} , tokenSource ) ; // give tokenSource in constructor
searcher . FilesFound += ( sender , arg ) => // subscribe on FilesFound event
{
lock ( locker ) // using a lock is obligatory
{
arg . Files . ForEach ( ( f ) =>
{
files . Add ( f ) ; // add the next part of the received files to the results list
Console . WriteLine ( $" File location: { f . FullName } , n Creation.Time: { f . CreationTime } " ) ;
} ) ;
if ( files . Count >= 10 ) // one can choose any stopping condition
searcher . StopSearch ( ) ;
}
} ;
searcher . SearchCompleted += ( sender , arg ) => // subscribe on SearchCompleted event
{
if ( arg . IsCanceled ) // check whether StopSearch() called
Console . WriteLine ( " Search stopped. " ) ;
else
Console . WriteLine ( " Search completed. " ) ;
Console . WriteLine ( $" Quantity of files: { files . Count } " ) ; // show amount of finding files
} ;
searcher . StartSearchAsync ( ) ;
// start search process as an asynchronous operation that doesn't block the called thread
}
}
Beachten Sie, dass nicht alle FilesFound
-Ereignishandler threadsicher sind. Um den Verlust von Ergebnissen zu verhindern, sollte daher das Schlüsselwort lock
verwendet werden, wie Sie im obigen Beispiel sehen können, oder die threadsichere Sammlung aus System.Collections.Concurrent
-Namespace verwendet werden.
Es gibt 2 zusätzliche Parameter, die man einstellen kann. Dies sind handlerOption
und suppressOperationCanceledException
. ExecuteHandlers handlerOption
stellt eine Instanz der ExecuteHandlers
-Enumeration dar, die angibt, wo FilesFound-Ereignishandler ausgeführt werden:
InCurrentTask
bedeutet, dass FileFound
-Ereignishandler in der Aufgabe ausgeführt werden, in der Dateien gefunden wurden.InNewTask
bedeutet, dass FilesFound
-Ereignishandler in einer neuen Aufgabe ausgeführt werden. Der Standardwert ist InCurrentTask
. Dies ist in den meisten Fällen vorteilhafter. InNewTask
Wert sollte nur verwendet werden, wenn Handler sehr anspruchsvolle Arbeiten ausführen, die viel Zeit in Anspruch nehmen, z. B. das Parsen jeder gefundenen Datei. bool suppressOperationCanceledException
bestimmt, ob die Unterdrückung von „OperationCanceledException“ erforderlich ist. Wenn der Parameter „ suppressOperationCanceledException
den Wert false
hat und die Methode „StopSearch()“ aufgerufen wird, wird die OperationCanceledException
ausgelöst. In diesem Fall müssen Sie die Ausnahme manuell bearbeiten. Wenn der Parameter suppressOperationCanceledException
den Wert true
hat und die Methode „StopSearch()“ aufgerufen wird, wird die OperationCanceledException
automatisch verarbeitet und Sie müssen sie nicht abfangen. Der Standardwert ist true
.
Beispiel:
CancellationTokenSource tokenSource = new CancellationTokenSource ( ) ;
FileSearcher searcher = new FileSearcher ( @"D:Program Files" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".{1,5}[Ss]ome[Pp]attern.txt$" ) && ( f . Length >= 8192 ) ; // 8192b == 8Kb
} , tokenSource , ExecuteHandlers . InNewTask , true ) ; // suppressOperationCanceledException == true
Die Klassen FileSearcher
und DirectorySearcher
können nur in einem Verzeichnis (und sicherlich in allen Unterverzeichnissen) suchen, aber was ist, wenn Sie die Suche in mehreren Verzeichnissen gleichzeitig durchführen möchten?
Natürlich können Sie einige Instanzen der Klasse FileSearcher
(oder DirectorySearcher
) erstellen und diese gleichzeitig starten, aber für jede von Ihnen erstellte Instanz treten FilesFound
(oder DirectoriesFound
)-Ereignisse auf. In der Regel ist es unbequem. Die Klassen FileSearcherMultiple
und DirectorySearcherMultiple
sollen dieses Problem lösen. Sie ähneln FileSearcher
und DirectorySearcher
können jedoch eine Suche in mehreren Verzeichnissen durchführen. Der Unterschied zwischen FileSearcher
und FileSearcherMultiple
besteht darin, dass der Konstruktor der Multiple
-Klasse eine Liste von Verzeichnissen anstelle eines Verzeichnisses akzeptiert.
Beispiel:
List < string > folders = new List < string >
{
@"C:UsersPublic" ,
@"C:WindowsSystem32" ,
@"D:Program Files" ,
@"D:Program Files (x86)"
} ; // list of search directories
List < string > keywords = new List < string > { " word1 " , " word2 " , " word3 " } ; // list of search keywords
FileSearcherMultiple multipleSearcher = new FileSearcherMultiple ( folders , ( f ) =>
{
if ( f . CreationTime >= new DateTime ( 2015 , 3 , 15 ) &&
( f . Extension == " .cs " || f . Extension == " .sln " ) )
{
foreach ( var keyword in keywords )
if ( f . Name . Contains ( keyword ) )
return true ;
}
return false ;
} , tokenSource , ExecuteHandlers . InCurrentTask , true ) ;
Es wird dringend empfohlen, das Schlüsselwort „await“ zu verwenden, wenn Sie eine asynchrone Methode verwenden. Es ermöglicht, mögliche Ausnahmen von der Methode für die folgende Verarbeitung abzurufen, was im nächsten Codebeispiel demonstriert wird. Der Einfachheit halber wurde die Fehlerverarbeitung in den vorherigen Beispielen übersprungen.
Beispiel:
using System ;
using System . Collections . Generic ;
using System . Diagnostics ;
using System . IO ;
using System . Text . RegularExpressions ;
using System . Threading ;
using FastSearchLibrary ;
namespace SearchWithAwait
{
class Program
{
private static object locker = new object ( ) ;
private static List < FileInfo > files ;
private static Stopwatch stopWatch ;
static void Main ( string [ ] args )
{
string searchPattern = @".mp4$" ;
StartSearch ( searchPattern ) ;
Console . ReadKey ( true ) ;
}
private static async void StartSearch ( string pattern )
{
stopWatch = new Stopwatch ( ) ;
stopWatch . Start ( ) ;
Console . WriteLine ( " Search has been started. n " ) ;
files = new List < FileInfo > ( ) ;
List < string > searchDirectories = new List < string >
{
@"C:" ,
@"D:"
} ;
FileSearcherMultiple searcher = new FileSearcherMultiple ( searchDirectories , ( f ) =>
{
return Regex . IsMatch ( f . Name , pattern ) ;
} , new CancellationTokenSource ( ) ) ;
searcher . FilesFound += Searcher_FilesFound ;
searcher . SearchCompleted += Searcher_SearchCompleted ;
try
{
await searcher . StartSearchAsync ( ) ;
}
catch ( AggregateException ex )
{
Console . WriteLine ( $" Error occurred: { ex . InnerException . Message } " ) ;
}
catch ( Exception ex )
{
Console . WriteLine ( $" Error occurred: { ex . Message } " ) ;
}
finally
{
Console . Write ( " n Press any key to continue... " ) ;
}
}
private static void Searcher_FilesFound ( object sender , FileEventArgs arg )
{
lock ( locker ) // using of the lock is mandatory
{
arg . Files . ForEach ( ( f ) =>
{
files . Add ( f ) ; // add the next part of the received files to the results list
Console . WriteLine ( $" File location: { f . FullName } n Creation.Time: { f . CreationTime } n " ) ;
} ) ;
}
}
private static void Searcher_SearchCompleted ( object sender , SearchCompletedEventArgs arg )
{
stopWatch . Stop ( ) ;
if ( arg . IsCanceled ) // check whether StopSearch() called
Console . WriteLine ( " Search stopped. " ) ;
else
Console . WriteLine ( " Search completed. " ) ;
Console . WriteLine ( $" Quantity of files: { files . Count } " ) ; // show amount of finding files
Console . WriteLine ( $" Spent time: { stopWatch . Elapsed . Minutes } min { stopWatch . Elapsed . Seconds } s { stopWatch . Elapsed . Milliseconds } ms " ) ;
}
}
}
Es gibt eine Windows-Beschränkung auf 260 Zeichen für den vollständigen Namen von Dateien. Im Allgemeinen ignoriert die Bibliothek solche „langen“ Pfade. Wenn Sie diese Einschränkung jedoch umgehen möchten, sollten Sie die folgenden Schritte befolgen:
<Project name>
im Projektmappen-Explorer aus, klicken Sie mit der rechten Maustaste -> Add
-> New item
-> Application manifest file
. Fügen Sie dann den Inhalt dieser Datei vor dem letzten geschlossenen Tag zum Manifest hinzu.HKLMSYSTEMCurrentControlSetControlFileSystem
Erstellen Sie dann den Parameter LongPathsEnabled
(Typ REG_DWORD) mit 1
Wert. Es hängt von der Leistung Ihres Computers und der aktuellen Auslastung ab, aber normalerweise werden Fast
Methoden und die Instanzmethode StartSearch()
mindestens zweimal schneller ausgeführt als einfache rekursive Ein-Thread-Algorithmen.