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
に、 4.6.2
以上を使用する場合は 4.6.2 に設定します: [プロジェクト] -> [プロパティ] -> [ターゲット フレームワーク] 次のクラスは検索機能を提供します。
FileSearcher
クラスとDirectorySearcher
には、さまざまな基準による検索を実行できる静的メソッドが含まれています。これらのメソッドは、実行が完全に完了した場合にのみ結果を返します。string folder
- 検索開始ディレクトリstring pattern
- パス内のファイル名と照合する検索文字列。このパラメーターには、有効なリテラル パスとワイルドカード (* および ?) 文字の組み合わせを含めることができますが、正規表現はサポートされていません。例:
List < FileInfo > files = FileSearcher . GetFiles ( @"C:Users" , " *.txt " ) ;
1 つのスレッド メソッドを使用して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()
メソッドを呼び出して検索プロセスを停止したかどうかを定義する値を含むbool IsCanceled { get; }
。検索プロセスの停止の可能性を取得するには、CancelTokenSource パラメーターを受け入れるコンストラクターを使用する必要があります。例:
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
パラメーターは、FilesFound イベント ハンドラーが実行される場所を指定するExecuteHandlers
列挙のインスタンスを表します。
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
クラスは 1 つのディレクトリ (およびすべてのサブディレクトリ) 内でのみ検索できますが、複数のディレクトリで同時に検索を実行したい場合はどうすればよいでしょうか。
もちろん、 FileSearcher
(またはDirectorySearcher
) クラスのインスタンスをいくつか作成し、同時に起動することもできますが、作成したインスタンスごとにFilesFound
(またはDirectoriesFound
) イベントが発生します。原則として、それは不便です。 FileSearcherMultiple
クラスとDirectorySearcherMultiple
クラスは、この問題を解決することを目的としています。これらはFileSearcher
およびDirectorySearcher
に似ていますが、複数のディレクトリで検索を実行できます。 FileSearcher
とFileSearcherMultiple
の違いは、 Multiple
クラスのコンストラクターが 1 つのディレクトリではなくディレクトリのリストを受け入れることです。
例:
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()
単純な 1 スレッド再帰アルゴリズムよりも少なくとも 2 倍高速に実行されます。