Estamos em estado de guerra com a Rússia desde 24 de fevereiro de 2022. Para ajudar a Ucrânia a alcançar a vitória o mais rápido possível, por favor, ignore todos os produtos, empresas, projetos russos... Tudo.
Você também pode ajudar as Forças Armadas da Ucrânia aqui: https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi
Libertaremos a nossa pátria dos invasores russos e salvaremos a Europa do agressivo e desumano regime russo. Eu prometo.
Se você deseja me apoiar pessoalmente, é possível fazê-lo aqui: https://ko-fi.com/VladPVS
A biblioteca .NET multithreading que oferece a oportunidade de localizar rapidamente arquivos ou diretórios usando diferentes critérios de pesquisa.
A versão .NET Core está disponível aqui.
A ferramenta de pesquisa de arquivos MIF é baseada nesta biblioteca. Você pode tentar se quiser estimar a velocidade do trabalho agora.
using FastSearchLibrary;
4.5.1
se você usar v1.1.6.1 da biblioteca ou 4.6.2
se usar pelo menos v1.1.7.2: Projeto -> Propriedades -> Estrutura de destino As próximas aulas fornecem funcionalidade de pesquisa:
FileSearcher
e DirectorySearcher
contêm métodos estáticos que permitem executar pesquisas por diferentes critérios. Esses métodos retornam resultados somente quando completam a execução.string folder
- inicia o diretório de pesquisastring pattern
- a string de pesquisa para corresponder aos nomes dos arquivos no caminho. Este parâmetro pode conter uma combinação de caminho literal válido e caracteres curinga (* e ?), mas não oferece suporte a expressões regulares.Exemplos:
List < FileInfo > files = FileSearcher . GetFiles ( @"C:Users" , " *.txt " ) ;
Encontra todos os arquivos *.txt
em C:Users
usando um método de thread.
List < FileInfo > files = FileSearcher . GetFilesFast ( @"C:Users" , " *SomePattern*.txt " ) ;
Encontra todos os arquivos que correspondem ao padrão apropriado usando vários threads no pool de threads.
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"C:" , " a?.txt " ) ;
Encontra todos os arquivos que correspondem ao padrão apropriado usando vários threads no pool de threads como uma operação assíncrona.
string folder
- inicia o diretório de pesquisaFunc<FileInfo, bool> isValid
- delegado que determina o algoritmo de seleção de arquivos.Exemplos:
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 ;
} ) ;
Localiza todos os arquivos que correspondem às condições apropriadas usando vários threads no pool de threads como uma operação assíncrona.
Você também pode usar expressões regulares:
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"D:" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".*Imagine[s_-]Dragons.*.mp3$" ) ;
} ) ;
Encontra todos os arquivos que correspondem à expressão regular apropriada usando vários threads no pool de threads como uma operação assíncrona.
Se você deseja executar alguma pesquisa complicada com obtenção de resultados em tempo real, você deve usar a instância da classe FileSearcher
, que possui várias sobrecargas de construtor. A classe FileSearcher
inclui os próximos eventos:
event EventHandler<FileEventArgs> FilesFound
- dispara quando a próxima parte dos arquivos é encontrada. O evento inclui List<FileInfo> Files { get; }
propriedade que contém uma lista de arquivos encontrados.event EventHandler<SearchCompleted> SearchCompleted
- é acionado quando o processo de pesquisa é concluído ou interrompido. O evento inclui bool IsCanceled { get; }
propriedade que contém o valor que define se o processo de pesquisa foi interrompido pela chamada do método StopSearch()
. Para obter a possibilidade de parar o processo de pesquisa, é necessário usar um construtor que aceite o parâmetro CancellationTokenSource.Exemplo:
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
}
}
Observe que todos os manipuladores de eventos FilesFound
não são thread-safe, portanto, para evitar a perda de resultados, deve-se usar a palavra-chave lock
, como você pode ver no exemplo acima, ou usar a coleção thread-safe do namespace System.Collections.Concurrent
.
Existem 2 parâmetros adicionais que podem ser definidos. Estes são handlerOption
e suppressOperationCanceledException
. O parâmetro ExecuteHandlers handlerOption
representa a instância da enumeração ExecuteHandlers
que especifica onde os manipuladores de eventos FilesFound são executados:
InCurrentTask
significa que os manipuladores de eventos FileFound
serão executados na tarefa onde os arquivos foram encontrados.InNewTask
significa que os manipuladores de eventos FilesFound
serão executados na nova tarefa. O valor padrão é InCurrentTask
. É mais preferencialmente na maioria dos casos. O valor InNewTask
deve ser usado somente se os manipuladores executarem um trabalho muito sofisticado que leva muito tempo, por exemplo, análise de cada arquivo encontrado. O parâmetro bool suppressOperationCanceledException
determina se é necessário suprimir OperationCanceledException. Se o parâmetro suppressOperationCanceledException
tiver valor false
e o método StopSearch() for chamado, a OperationCanceledException
será lançada. Neste caso você terá que processar a exceção manualmente. Se o parâmetro suppressOperationCanceledException
tiver valor true
e o método StopSearch() for chamado, a OperationCanceledException
será processada automaticamente e você não precisará capturá-la. O valor padrão é true
.
Exemplo:
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
As classes FileSearcher
e DirectorySearcher
podem pesquisar apenas em um diretório (e certamente em todos os subdiretórios), mas e se você quiser realizar pesquisas em vários diretórios ao mesmo tempo?
Claro, você pode criar algumas instâncias da classe FileSearcher
(ou DirectorySearcher
) e iniciá-las simultaneamente, mas os eventos FilesFound
(ou DirectoriesFound
) ocorrerão para cada instância que você criar. Via de regra, é inconveniente. As classes FileSearcherMultiple
e DirectorySearcherMultiple
destinam-se a resolver este problema. Eles são semelhantes ao FileSearcher
e DirectorySearcher
, mas podem executar pesquisas em vários diretórios. A diferença entre FileSearcher
e FileSearcherMultiple
é que o construtor da classe Multiple
aceita uma lista de diretórios em vez de um diretório.
Exemplo:
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 ) ;
É altamente recomendável usar a palavra-chave "await" ao usar qualquer método assíncrono. Permite obter possíveis exceções do método para processamento seguinte, que é demonstrado no próximo exemplo de código. O processamento de erros nos exemplos anteriores foi ignorado por questões de simplicidade.
Exemplo:
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 " ) ;
}
}
}
Há uma limitação do Windows de 260 símbolos no nome completo dos arquivos. Em casos comuns, a biblioteca irá ignorar esses caminhos "longos". Mas se você quiser contornar essa limitação você deve seguir os próximos passos:
<Project name>
no Solution Explorer, clique com o botão direito do mouse -> Add
-> New item
-> Application manifest file
. Em seguida, adicione o conteúdo deste arquivo ao manifesto antes da última tag fechada.HKLMSYSTEMCurrentControlSetControlFileSystem
Em seguida, crie o parâmetro LongPathsEnabled
(tipo REG_DWORD) com 1
valor. Depende do desempenho do seu computador, da carga atual, mas geralmente os métodos Fast
e o método de instância StartSearch()
são executados pelo menos 2 vezes mais rápido do que o algoritmo recursivo simples de um thread.