はじめに
みなさん、毎日windowsでファイルしてますか!?
私はしています。どこかの試算だとファイル検索に使用している時間は、1年で1か月に相当するとか聞いたことがあります。
そこで、私がWindows最速のファイル検索コマンドを探しました。
前提
- Windows
- 閲覧権限があるフォルダ
- Powershell
Windows 最速コマンド
以下の5つのコマンドで計測しました。
また、計測にはMeasure-Commandを使用しています。
-Expressionで計測したいコマンドを指定することで計測できます。
使用例: Measure-Command -Expression { Get-Process }
| コマンド | 説明 | 使用例 |
|---|---|---|
| Get-ChildItem | PowerShellの標準コマンド Get-ChildItemを使い、指定したパターンに一致するファイルを再帰的に探索します。 |
Get-ChildItem -Path $rootPath -Filter $pattern -Recurse -ErrorAction SilentlyContinue |
| [System.IO.Directory]::EnumerateFiles | .NETのメソッドである [System.IO.Directory]::EnumerateFiles を使い、指定したパターンに一致するファイルを再帰的に探索します。 |
[System.IO.Directory]::EnumerateFiles($rootPath, $pattern, 'AllDirectories') |
| ls | PowerShellの別名(エイリアス)である ls(本来は Get-ChildItemのエイリアス)を使い、指定したパターンに一致するファイルを再帰的に探索します。 |
ls -Path $rootPath -Filter $pattern -Recurse -ErrorAction SilentlyContinue |
| DirectoryInfo | .NETの System.IO.DirectoryInfoクラスを使い、指定したパターンに一致するファイルを再帰的に探索します。 |
$di = New-Object System.IO.DirectoryInfo($rootPath); $di.GetFiles($pattern, 'AllDirectories') |
| robocopy |
robocopyコマンドを使い、指定したパターンに一致するファイルを再帰的に探索します。 |
robocopy $rootPath NULL $pattern /L /S /NJH /NJS /NDL /NS |
これらのコマンドは、すべてファイルを探索するためのものですが、各コマンドにはその特性や速度、そして使用状況や環境による限定的な問題(OneDriveとの相性など)が存在します。
スクリプト紹介
1. Get-ChildItemによる検索と計測
基本の検索はGet-ChildItemじゃないでしょうか。
PowerShellの標準コマンドで、指定されたパスのアイテム(ディレクトリやファイル)を取得します。
-Pathで指定されたパス($rootPath)から、-Filterで指定されたパターン($pattern)に一致するアイテムを再帰的に(-Recurse)探索しています。-ErrorAction SilentlyContinueはエラーが発生しても処理を続行するためのオプションです。
$getChildItemTime = Measure-Command -Expression {
Get-ChildItem -Path $rootPath -Filter $pattern -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$_.FullName
}
}
Write-Output "Get-ChildItem time: $($getChildItemTime.TotalMilliseconds) ms"
2. [System.IO.Directory]::EnumerateFilesによる検索と計測
.NET Frameworkのメソッドで、指定されたパスからパターンに一致するファイルを再帰的に検索します。ここでは$rootPathから$patternに一致するファイルを再帰的に('AllDirectories')探索しています。
$enumerateFilesTime = Measure-Command -Expression {
[System.IO.Directory]::EnumerateFiles($rootPath, $pattern, 'AllDirectories')
}
Write-Output "[System.IO.Directory]::EnumerateFiles time: $($enumerateFilesTime.TotalMilliseconds) ms"
3. lsによる検索と計測
みなさんおなじみのlsですね、実は検索もできます。
lsはUnix系システムで使われるコマンドで、PowerShellではGet-ChildItemのエイリアス(別名)として機能します。このコマンドも$rootPathから$patternに一致するアイテムを再帰的に探索します。
$lsTime = Measure-Command -Expression {
ls -Path $rootPath -Filter $pattern -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$_.FullName
}
}
Write-Output "ls time: $($lsTime.TotalMilliseconds) ms"
4. DirectoryInfoによる検索と計測
System.IO.DirectoryInfoは.NET Frameworkのクラスで、ファイルシステムのディレクトリを表します。GetFilesメソッドは指定されたパターンに一致するファイルを再帰的に取得します。ここでは$rootPathから$patternに一致するファイルを再帰的に取得しています。
$directoryInfoTime = Measure-Command -Expression {
$di = New-Object System.IO.DirectoryInfo($rootPath)
$di.GetFiles($pattern, 'AllDirectories')
}
Write-Output "DirectoryInfo time: $($directoryInfoTime.TotalMilliseconds) ms"
5. robocopyによる検索と計測
robocopyはRobust File Copyの略で、Windowsで使用される強力なファイルコピーのコマンドです。ただし、ここではファイルのコピーではなく、/Lオプションによってリストのみを生成してファイルを探索しています。/Sオプションはサブディレクトリも探索することを意味し、/NJH, /NJS, /NDL, /NSはヘッダ、サマリ、ディレクトリ名、ファイルサイズの出力を抑制するためのオプションです。
$robocopyTime = Measure-Command -Expression {
robocopy $rootPath NULL $pattern /L /S /NJH /NJS /NDL /NS | Out-Null
}
Write-Output "robocopy time: $($robocopyTime.TotalMilliseconds) ms"
最速はだれ!?
では計測していきます!
Explorerのフォルダ検索時間(ローカルフォルダ)
| コマンド | 実行時間 (s) |
|---|---|
| robocopy | 0.233 |
| [System.IO.Directory]::EnumerateFiles | 0.244 |
| DirectoryInfo | 0.280 |
| Get-ChildItem | 0.417 |
| ls | 0.533 |
OneDriveの検索時間
Onedriveとの相性は相当あるっぽいですね。
| コマンド | 実行時間 (s) |
|---|---|
| robocopy | 0.047 |
| [System.IO.Directory]::EnumerateFiles | 8.895 |
| DirectoryInfo | 7.688 |
| Get-ChildItem | 57.780 |
| ls | 70.540 |
ランキング
| ランキング | OneDriveの検索 | Explorerの検索 |
|---|---|---|
| 1 (最速) | robocopy | robocopy |
| 2 | [System.IO.Directory]::EnumerateFiles | [System.IO.Directory]::EnumerateFiles |
| 3 | DirectoryInfo | DirectoryInfo |
| 4 | Get-ChildItem | Get-ChildItem |
| 5 (最遅) | ls | ls |
これらの結果から、robocopyが最適であることがわかりました!
使ったことなかったし、存在を知らなかった。。
みなさん、あしたからrobocopyを使ってファイル検索しましょう(なくさないようなフォルダ管理をするのが一番良い)
ソース全体
$rootPath = "C:\Users\sakaj\OneDrive - WellBee\" # 探索したいディレクトリのパス
$pattern = "hoge.txt" # 検索したいパターンを指定
# Get-ChildItemによる検索と計測
$getChildItemTime = Measure-Command -Expression {
Get-ChildItem -Path $rootPath -Filter $pattern -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$_.FullName
}
}
Write-Output "Get-ChildItem time: $($getChildItemTime.TotalMilliseconds) ms"
# [System.IO.Directory]::EnumerateFilesによる検索と計測
$enumerateFilesTime = Measure-Command -Expression {
[System.IO.Directory]::EnumerateFiles($rootPath, $pattern, 'AllDirectories')
}
Write-Output "[System.IO.Directory]::EnumerateFiles time: $($enumerateFilesTime.TotalMilliseconds) ms"
# lsによる検索と計測
$lsTime = Measure-Command -Expression {
ls -Path $rootPath -Filter $pattern -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$_.FullName
}
}
Write-Output "ls time: $($lsTime.TotalMilliseconds) ms"
# DirectoryInfoによる検索と計測
$directoryInfoTime = Measure-Command -Expression {
$di = New-Object System.IO.DirectoryInfo($rootPath)
$di.GetFiles($pattern, 'AllDirectories')
}
Write-Output "DirectoryInfo time: $($directoryInfoTime.TotalMilliseconds) ms"
# robocopyによる検索と計測
$robocopyTime = Measure-Command -Expression {
robocopy $rootPath NULL $pattern /L /S /NJH /NJS /NDL /NS | Out-Null
}
Write-Output "robocopy time: $($robocopyTime.TotalMilliseconds) ms"