Estamos en estado de guerra con Rusia desde el 24 de febrero de 2022. Para ayudar a Ucrania a lograr la victoria lo antes posible, por favor, ignoren todos los productos, empresas, proyectos rusos... Todo.
También puedes ayudar a las Fuerzas Armadas de Ucrania aquí: https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi
Liberaremos a nuestra Patria de los invasores rusos y salvaremos a Europa del agresivo e inhumano régimen ruso. Prometo.
Si desea apoyarme personalmente, es posible hacerlo aquí: https://ko-fi.com/VladPVS
La biblioteca .NET multiproceso que brinda la oportunidad de buscar rápidamente archivos o directorios utilizando diferentes criterios de búsqueda.
La versión .NET Core está disponible aquí.
La herramienta de búsqueda de archivos MIF se basa en esta biblioteca. Puedes probarlo si quieres estimar la velocidad de trabajo ahora mismo.
using FastSearchLibrary;
4.5.1
si usa la versión 1.1.6.1 de la biblioteca o 4.6.2
si usa al menos la v1.1.7.2: Proyecto -> Propiedades -> Marco de destino Las siguientes clases proporcionan funcionalidad de búsqueda:
FileSearcher
y DirectorySearcher
contienen métodos estáticos que permiten ejecutar búsquedas según diferentes criterios. Estos métodos devuelven resultados solo cuando completan completamente la ejecución.string folder
- iniciar directorio de búsquedastring pattern
: la cadena de búsqueda que se debe comparar con los nombres de los archivos en la ruta. Este parámetro puede contener una combinación de ruta literal válida y caracteres comodín (* y ?), pero no admite expresiones regulares.Ejemplos:
List < FileInfo > files = FileSearcher . GetFiles ( @"C:Users" , " *.txt " ) ;
Encuentra todos los archivos *.txt
en C:Users
utilizando un método de subproceso.
List < FileInfo > files = FileSearcher . GetFilesFast ( @"C:Users" , " *SomePattern*.txt " ) ;
Encuentra todos los archivos que coinciden con el patrón apropiado utilizando varios subprocesos en el grupo de subprocesos.
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"C:" , " a?.txt " ) ;
Encuentra todos los archivos que coinciden con el patrón apropiado utilizando varios subprocesos en el grupo de subprocesos como una operación asincrónica.
string folder
- iniciar directorio de búsquedaFunc<FileInfo, bool> isValid
: delegado que determina el algoritmo de selección de archivos.Ejemplos:
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 ;
} ) ;
Encuentra todos los archivos que coinciden con las condiciones adecuadas utilizando varios subprocesos en el grupo de subprocesos como una operación asincrónica.
También puedes usar expresiones regulares:
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"D:" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".*Imagine[s_-]Dragons.*.mp3$" ) ;
} ) ;
Encuentra todos los archivos que coinciden con la expresión regular adecuada utilizando varios subprocesos en el grupo de subprocesos como una operación asincrónica.
Si desea ejecutar alguna búsqueda complicada con resultados en tiempo real, debe usar la instancia de la clase FileSearcher
, que tiene varias sobrecargas de constructor. La clase FileSearcher
incluye los siguientes eventos:
event EventHandler<FileEventArgs> FilesFound
: se activa cuando se encuentra la siguiente parte de los archivos. El evento incluye List<FileInfo> Files { get; }
propiedad que contiene una lista de archivos de búsqueda.event EventHandler<SearchCompleted> SearchCompleted
: se activa cuando se completa o se detiene el proceso de búsqueda. El evento incluye bool IsCanceled { get; }
propiedad que contiene un valor que define si el proceso de búsqueda se detuvo llamando al método StopSearch()
. Para detener la posibilidad del proceso de búsqueda, se debe utilizar un constructor que acepte el parámetro CancellationTokenSource.Ejemplo:
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
}
}
Tenga en cuenta que todos los controladores de eventos FilesFound
no son seguros para subprocesos, por lo que para evitar que se pierdan resultados, se debe usar la palabra clave lock
como puede ver en el ejemplo anterior o usar una colección segura para subprocesos del espacio de nombres System.Collections.Concurrent
.
Hay 2 parámetros adicionales que se pueden configurar. Estos son handlerOption
y suppressOperationCanceledException
. El parámetro ExecuteHandlers handlerOption
representa una instancia de la enumeración ExecuteHandlers
que especifica dónde se ejecutan los controladores de eventos FilesFound:
InCurrentTask
significa que los controladores de eventos FileFound
se ejecutarán en esa tarea donde se encontraron los archivos.InNewTask
significa que los controladores de eventos FilesFound
se ejecutarán en una nueva tarea. El valor predeterminado es InCurrentTask
. Es más preferible en la mayoría de los casos. El valor InNewTask
se debe utilizar sólo si los controladores ejecutan un trabajo muy sofisticado que requiere mucho tiempo, por ejemplo, el análisis de cada archivo encontrado. El parámetro bool suppressOperationCanceledException
determina si es necesario suprimir OperationCanceledException. Si el parámetro suppressOperationCanceledException
tiene un valor false
y se llama al método StopSearch(), se generará OperationCanceledException
. En este caso deberá procesar la excepción manualmente. Si el parámetro suppressOperationCanceledException
tiene el valor true
y se llama al método StopSearch(), OperationCanceledException
se procesa automáticamente y no es necesario detectarlo. El valor predeterminado es true
.
Ejemplo:
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
Las clases FileSearcher
y DirectorySearcher
pueden buscar solo en un directorio (y seguramente en todos los subdirectorios), pero ¿qué sucede si desea realizar una búsqueda en varios directorios al mismo tiempo?
Por supuesto, puede crear algunas instancias de la clase FileSearcher
(o DirectorySearcher
) y ejecutarlas simultáneamente, pero se producirán eventos FilesFound
(o DirectoriesFound
) para cada instancia que cree. Como regla general, esto es un inconveniente. Las clases FileSearcherMultiple
y DirectorySearcherMultiple
están destinadas a resolver este problema. Son similares a FileSearcher
y DirectorySearcher
pero pueden ejecutar búsquedas en varios directorios. La diferencia entre FileSearcher
y FileSearcherMultiple
es que el constructor de la clase Multiple
acepta una lista de directorios en lugar de un directorio.
Ejemplo:
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 ) ;
Se recomienda encarecidamente utilizar la palabra clave "await" cuando utilice cualquier método asincrónico. Permite obtener posibles excepciones del método para el siguiente procesamiento, como se demuestra en el siguiente ejemplo de código. Por simplicidad, se ha omitido el procesamiento de errores en ejemplos anteriores.
Ejemplo:
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 " ) ;
}
}
}
Hay una limitación de Windows de 260 símbolos en el nombre completo de los archivos. En casos comunes, la biblioteca ignorará rutas tan "largas". Pero si quieres eludir esta limitación debes seguir los siguientes pasos:
<Project name>
en el Explorador de soluciones, haga clic con el botón derecho del mouse -> Add
-> New item
-> Application manifest file
. Luego agregue el contenido de este archivo al manifiesto antes de la última etiqueta cerrada.HKLMSYSTEMCurrentControlSetControlFileSystem
Luego cree el parámetro LongPathsEnabled
(escriba REG_DWORD) con 1
valor. Depende del rendimiento de su computadora y de la carga actual, pero generalmente los métodos Fast
y el método de instancia StartSearch()
se realizan al menos 2 veces más rápido que el algoritmo recursivo simple de un subproceso.