自2022年2月24日以来,我们与俄罗斯一直处于战争状态。为了帮助乌克兰尽快取得胜利,请忽略所有俄罗斯产品、公司、项目……一切。
您也可以在这里帮助乌克兰武装部队:https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi
我们将从俄罗斯侵略者手中解放我们的祖国,并从侵略性的、不人道的俄罗斯政权手中拯救欧洲。我保证。
如果您想亲自支持我,可以在这里进行:https://ko-fi.com/VladPVS
多线程 .NET 库提供使用不同搜索条件快速查找文件或目录的机会。
.NET Core 版本可在此处获取。
MIF 文件搜索工具基于该库。如果您现在想估计工作速度,您可以尝试一下。
using FastSearchLibrary;
4.5.1
如果使用至少 v1.1.7.2,则将目标 .NET 版本设置为4.6.2
:项目 -> 属性 -> 目标框架接下来的类提供搜索功能:
FileSearcher
和DirectorySearcher
类包含允许按不同条件执行搜索的静态方法。这些方法仅在完全完成执行时才返回结果。string folder
-开始搜索目录string pattern
- 与路径中的文件名匹配的搜索字符串。此参数可以包含有效的文字路径和通配符(* 和 ?) 字符的组合,但不支持正则表达式。示例:
List < FileInfo > files = FileSearcher . GetFiles ( @"C:Users" , " *.txt " ) ;
使用一种线程方法查找C:Users
中的所有*.txt
文件。
List < FileInfo > files = FileSearcher . GetFilesFast ( @"C:Users" , " *SomePattern*.txt " ) ;
使用线程池中的多个线程查找与适当模式匹配的所有文件。
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"C:" , " a?.txt " ) ;
使用线程池中的多个线程作为异步操作查找与适当模式匹配的所有文件。
string folder
-开始搜索目录Func<FileInfo, bool> isValid
- 确定文件选择算法的委托。示例:
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 ;
} ) ;
使用线程池中的多个线程作为异步操作查找与适当条件匹配的所有文件。
您还可以使用正则表达式:
Task < List < FileInfo > > task = FileSearcher . GetFilesFastAsync ( @"D:" , ( f ) =>
{
return Regex . IsMatch ( f . Name , @".*Imagine[s_-]Dragons.*.mp3$" ) ;
} ) ;
使用线程池中的多个线程作为异步操作查找与适当正则表达式匹配的所有文件。
如果您想执行一些复杂的搜索并获取实时结果,您应该使用FileSearcher
类的实例,该类具有各种构造函数重载。 FileSearcher
类包括以下事件:
event EventHandler<FileEventArgs> FilesFound
- 当找到文件的下一部分时触发。事件包括List<FileInfo> Files { get; }
包含查找文件列表的List<FileInfo> Files { get; }
。event EventHandler<SearchCompleted> SearchCompleted
- 当搜索过程完成或停止时触发。事件包括bool IsCanceled { get; }
属性包含定义搜索过程是否通过调用StopSearch()
方法停止的值。为了获得停止搜索过程的可能性,必须使用接受 CancellationTokenSource 参数的构造函数。例子:
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
}
}
请注意,所有FilesFound
事件处理程序都不是线程安全的,因此为了防止结果丢失,应使用lock
关键字(如上面的示例所示)或使用System.Collections.Concurrent
命名空间中的线程安全集合。
还有 2 个附加参数可以设置。它们是handlerOption
和suppressOperationCanceledException
。 ExecuteHandlers handlerOption
参数表示ExecuteHandlers
枚举的实例,该枚举指定在何处执行 FilesFound 事件处理程序:
InCurrentTask
值意味着FileFound
事件处理程序将在找到文件的任务中执行。InNewTask
值意味着FilesFound
事件处理程序将在新任务中执行。默认值为InCurrentTask
。在大多数情况下这是更优选的。仅当处理程序执行需要大量时间的非常复杂的工作(例如解析每个找到的文件)时,才应使用InNewTask
值。 bool suppressOperationCanceledException
参数决定是否需要抑制OperationCanceledException。如果suppressOperationCanceledException
参数的值为false
并且调用StopSearch()方法,则将抛出OperationCanceledException
。在这种情况下,您必须手动处理异常。如果suppressOperationCanceledException
参数的值为true
并且调用StopSearch() 方法,则OperationCanceledException
会自动处理,您无需捕获它。默认值为true
。
例子:
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
FileSearcher
和DirectorySearcher
类只能在一个目录中搜索(当然也可以在所有子目录中搜索),但是如果您想同时在多个目录中执行搜索怎么办?
当然,您可以创建FileSearcher
(或DirectorySearcher
)类的一些实例并同时启动它们,但您创建的每个实例都会发生FilesFound
(或DirectoriesFound
)事件。一般来说,这是不方便的。类FileSearcherMultiple
和DirectorySearcherMultiple
旨在解决此问题。它们与FileSearcher
和DirectorySearcher
类似,但可以在多个目录中执行搜索。 FileSearcher
和FileSearcherMultiple
之间的区别在于Multiple
类的构造函数接受目录列表而不是一个目录。
例子:
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 ) ;
强烈建议您在使用任何异步方法时使用“await”关键字。它允许从方法中获取可能的异常以进行后续处理,这将在下一个代码示例中进行演示。为了简单起见,前面示例中的错误处理已被跳过。
例子:
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 " ) ;
}
}
}
Windows 对文件全名有 260 个符号的限制。在常见情况下,库将忽略此类“长”路径。但如果您想规避此限制,您应该按照以下步骤操作:
<Project name>
,单击鼠标右键 -> Add
-> New item
-> Application manifest file
。然后将此文件的内容添加到清单中最后一个关闭标记之前。HKLMSYSTEMCurrentControlSetControlFileSystem
然后创建值为1
参数LongPathsEnabled
(类型 REG_DWORD)。这取决于您的计算机性能、当前加载,但通常Fast
方法和实例方法StartSearch()
执行速度至少比简单的单线程递归算法快 2 倍。