Nous sommes en guerre avec la Russie depuis le 24 février 2022. Pour aider l'Ukraine à remporter la victoire le plus rapidement possible, s'il vous plaît, ignorez tous les produits, entreprises, projets russes... Tout.
Vous pouvez également aider les Forces armées ukrainiennes ici : https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi
Nous libérerons notre patrie des envahisseurs russes et sauverons l’Europe du régime russe agressif et inhumain. Je le promets.
Si vous souhaitez me soutenir personnellement, c'est possible de le faire ici : https://ko-fi.com/VladPVS
La bibliothèque .NET multithreading qui offre la possibilité de rechercher rapidement des fichiers ou des répertoires en utilisant différents critères de recherche.
La version .NET Core est disponible ici.
L'outil de recherche de fichiers MIF est basé sur cette bibliothèque. Vous pouvez l'essayer si vous souhaitez estimer la vitesse de travail dès maintenant.
using FastSearchLibrary;
4.5.1
si vous utilisez la version 1.1.6.1 de la bibliothèque ou 4.6.2
si vous utilisez au moins la version 1.1.7.2 : Projet -> Propriétés -> Framework cible Les classes suivantes offrent une fonctionnalité de recherche :
FileSearcher
et DirectorySearcher
contiennent des méthodes statiques qui permettent d'exécuter une recherche selon différents critères. Ces méthodes renvoient le résultat uniquement lorsqu’elles terminent complètement leur exécution.string folder
- démarrer le répertoire de recherchestring pattern
: la chaîne de recherche à comparer aux noms des fichiers dans le chemin. Ce paramètre peut contenir une combinaison de chemin littéral valide et de caractères génériques (* et ?), mais ne prend pas en charge les expressions régulières.Exemples :
List < FileInfo > files = FileSearcher . GetFiles ( @"C:Users" , " *.txt " ) ;
Recherche tous les fichiers *.txt
dans C:Users
à l'aide d'une seule méthode de thread.
List < FileInfo > files = FileSearcher . GetFilesFast ( @"C:Users" , " *SomePattern*.txt " ) ;
Recherche tous les fichiers qui correspondent au modèle approprié à l'aide de plusieurs threads dans le pool de threads.
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"C:" , " a?.txt " ) ;
Recherche tous les fichiers qui correspondent au modèle approprié en utilisant plusieurs threads dans le pool de threads en tant qu'opération asynchrone.
string folder
- démarrer le répertoire de rechercheFunc<FileInfo, bool> isValid
- délégué qui détermine l'algorithme de sélection de fichiers.Exemples :
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 ;
} ) ;
Recherche tous les fichiers qui correspondent aux conditions appropriées à l’aide de plusieurs threads du pool de threads en tant qu’opération asynchrone.
Vous pouvez également utiliser des expressions régulières :
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"D:" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".*Imagine[s_-]Dragons.*.mp3$" ) ;
} ) ;
Recherche tous les fichiers qui correspondent à l'expression régulière appropriée en utilisant plusieurs threads dans le pool de threads en tant qu'opération asynchrone.
Si vous souhaitez exécuter une recherche complexe avec obtention de résultats en temps réel, vous devez utiliser une instance de la classe FileSearcher
, qui comporte diverses surcharges de constructeur. La classe FileSearcher
inclut les événements suivants :
event EventHandler<FileEventArgs> FilesFound
- se déclenche lorsque la partie suivante des fichiers est trouvée. L'événement inclut List<FileInfo> Files { get; }
propriété qui contient la liste des fichiers de recherche.event EventHandler<SearchCompleted> SearchCompleted
- se déclenche lorsque le processus de recherche est terminé ou arrêté. L'événement inclut bool IsCanceled { get; }
propriété qui contient une valeur qui définit si le processus de recherche s'est arrêté en appelant la méthode StopSearch()
. Pour obtenir la possibilité d’arrêter le processus de recherche, il faut utiliser un constructeur qui accepte le paramètre CancellationTokenSource.Exemple:
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
}
}
Notez que tous les gestionnaires d'événements FilesFound
ne sont pas thread-safe, donc pour éviter la perte de résultats, vous devez utiliser le mot-clé lock
comme vous pouvez le voir dans l'exemple ci-dessus ou utiliser la collection thread-safe de l'espace de noms System.Collections.Concurrent
.
Il existe 2 paramètres supplémentaires que l'on peut définir. Il s'agit de handlerOption
et suppressOperationCanceledException
. Le paramètre ExecuteHandlers handlerOption
représente une instance de l'énumération ExecuteHandlers
qui spécifie où les gestionnaires d'événements FilesFound sont exécutés :
InCurrentTask
signifie que les gestionnaires d'événements FileFound
seront exécutés dans la tâche où les fichiers ont été trouvés.InNewTask
signifie que les gestionnaires d’événements FilesFound
seront exécutés dans une nouvelle tâche. La valeur par défaut est InCurrentTask
. C'est plus préférable dans la plupart des cas. La valeur InNewTask
ne doit être utilisée que si les gestionnaires exécutent un travail très sophistiqué qui prend beaucoup de temps, par exemple l'analyse de chaque fichier trouvé. Le paramètre bool suppressOperationCanceledException
détermine s’il est nécessaire de supprimer OperationCanceledException. Si le paramètre suppressOperationCanceledException
a la valeur false
et que la méthode StopSearch() est appelée, OperationCanceledException
sera levée. Dans ce cas, vous devez traiter l'exception manuellement. Si le paramètre suppressOperationCanceledException
a la valeur true
et que la méthode StopSearch() est appelée, OperationCanceledException
est traitée automatiquement et vous n'avez pas besoin de l'intercepter. La valeur par défaut est true
.
Exemple:
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
Les classes FileSearcher
et DirectorySearcher
ne peuvent effectuer une recherche que dans un seul répertoire (et sûrement dans tous les sous-répertoires), mais que se passe-t-il si vous souhaitez effectuer une recherche dans plusieurs répertoires en même temps ?
Bien sûr, vous pouvez créer des instances de la classe FileSearcher
(ou DirectorySearcher
) et les lancer simultanément, mais des événements FilesFound
(ou DirectoriesFound
) se produiront pour chaque instance que vous créez. En règle générale, ce n'est pas pratique. Les classes FileSearcherMultiple
et DirectorySearcherMultiple
sont destinées à résoudre ce problème. Ils sont similaires à FileSearcher
et DirectorySearcher
mais peuvent exécuter une recherche dans plusieurs répertoires. La différence entre FileSearcher
et FileSearcherMultiple
est que le constructeur de la classe Multiple
accepte une liste de répertoires au lieu d'un seul répertoire.
Exemple:
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 ) ;
Il est fortement recommandé d'utiliser le mot-clé « attendre » lorsque vous utilisez une méthode asynchrone. Il permet d'obtenir d'éventuelles exceptions à la méthode pour suivre le traitement, comme le démontre l'exemple de code suivant. Le traitement des erreurs dans les exemples précédents a été ignoré par souci de simplicité.
Exemple:
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 " ) ;
}
}
}
Il existe une limitation Windows de 260 symboles sur le nom complet des fichiers. Dans les cas courants, la bibliothèque ignorera ces chemins "longs". Mais si vous souhaitez contourner cette limitation, vous devez suivre les étapes suivantes :
<Project name>
dans l'Explorateur de solutions, cliquez sur le bouton droit de la souris -> Add
-> New item
-> Application manifest file
. Ajoutez ensuite le contenu de ce fichier au manifeste avant la dernière balise fermée.HKLMSYSTEMCurrentControlSetControlFileSystem
Créez ensuite le paramètre LongPathsEnabled
(tapez REG_DWORD) avec 1
valeur. Cela dépend des performances de votre ordinateur et du chargement actuel, mais généralement les méthodes Fast
et la méthode d'instance StartSearch()
sont exécutées au moins 2 fois plus rapidement qu'un simple algorithme récursif à un thread.