Finder 組件
Finder 組件透過直覺式的流暢介面,根據不同條件(名稱、檔案大小、修改時間等)尋找檔案和目錄。
安裝
1
$ composer require symfony/finder
注意
如果您在 Symfony 應用程式之外安裝此組件,您必須在程式碼中引入 vendor/autoload.php
檔案,以啟用 Composer 提供的類別自動載入機制。請閱讀這篇文章以取得更多詳細資訊。
用法
Finder 類別用於尋找檔案和/或目錄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
use Symfony\Component\Finder\Finder;
$finder = new Finder();
// find all files in the current directory
$finder->files()->in(__DIR__);
// check if there are any search results
if ($finder->hasResults()) {
// ...
}
foreach ($finder as $file) {
$absoluteFilePath = $file->getRealPath();
$fileNameWithExtension = $file->getRelativePathname();
// ...
}
$file
變數是 SplFileInfo 的實例,它擴展了 PHP 原生的 SplFileInfo,以提供處理相對路徑的方法。
警告
Finder
物件不會自動重設其內部狀態。這表示如果您不希望獲得混合的結果,則需要建立一個新的實例。
搜尋檔案和目錄
此組件提供了許多方法來定義搜尋條件。它們都可以鏈式調用,因為它們實作了流暢介面。
位置
位置是唯一強制性的條件。它告訴 Finder 要使用哪個目錄進行搜尋
1
$finder->in(__DIR__);
透過鏈式調用 in(),在多個位置進行搜尋
1 2 3 4 5
// search inside *both* directories
$finder->in([__DIR__, '/elsewhere']);
// same as above
$finder->in(__DIR__)->in('/elsewhere');
使用 *
作為萬用字元,以在符合模式的目錄中搜尋(每個模式都必須解析為至少一個目錄路徑)
1
$finder->in('src/Symfony/*/*/Resources');
使用 exclude() 方法排除符合條件的目錄
1 2
// directories passed as argument must be relative to the ones defined with the in() method
$finder->in(__DIR__)->exclude('ruby');
也可以忽略您沒有權限讀取的目錄
1
$finder->ignoreUnreadableDirs()->in(__DIR__);
由於 Finder 使用 PHP 迭代器,您可以傳遞任何 URL,並搭配支援的 URL 樣式協定的 PHP 封裝器 (ftp://
、zlib://
等)
1 2 3 4 5
// always add a trailing slash when looking for in the FTP root dir
$finder->in('ftp://example.com/');
// you can also look for in a FTP directory
$finder->in('ftp://example.com/pub/');
它也適用於使用者定義的串流
1 2 3 4 5 6 7 8 9 10 11
use Symfony\Component\Finder\Finder;
// register a 's3://' wrapper with the official AWS SDK
$s3Client = new Aws\S3\S3Client([/* config options */]);
$s3Client->registerStreamWrapper();
$finder = new Finder();
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
foreach ($finder->in('s3://bucket-name') as $file) {
// ... do something with the file
}
參見
請閱讀 PHP 串流 文件,以瞭解如何建立自己的串流。
檔案或目錄
預設情況下,Finder 會同時傳回檔案和目錄。如果您只需要尋找檔案或目錄,請使用 files() 和 directories() 方法
1 2 3 4 5
// look for files only; ignore directories
$finder->files();
// look for directories only; ignore files
$finder->directories();
如果您想要追蹤符號連結,請使用 followLinks()
方法
1
$finder->files()->followLinks();
請注意,此方法會追蹤連結,但不會解析它們。請考慮以下檔案或目錄結構
1 2 3 4 5 6 7 8
├── folder1/
│ ├──file1.txt
│ ├── file2link (symbolic link to folder2/file2.txt file)
│ └── folder3link (symbolic link to folder3/ directory)
├── folder2/
│ └── file2.txt
└── folder3/
└── file3.txt
如果您嘗試透過 $finder->files()->in('/path/to/folder1/')
在 folder1/
中尋找所有檔案,您將會得到以下結果
- 當不使用
followLinks()
方法時:file1.txt
和file2link
(此連結未解析)。folder3link
不會出現在結果中,因為它未被追蹤或解析; - 當使用
followLinks()
方法時:file1.txt
、file2link
(此連結仍然未解析) 和folder3/file3.txt
(此檔案出現在結果中,因為folder1/folder3link
連結已被追蹤)。
版本控制檔案
版本控制系統(簡稱 "VCS"),例如 Git 和 Mercurial,會建立一些特殊檔案來儲存其元數據。預設情況下,在尋找檔案和目錄時會忽略這些檔案,但您可以使用 ignoreVCS()
方法來變更此行為
1
$finder->ignoreVCS(false);
如果搜尋目錄及其子目錄包含 .gitignore
檔案,您可以使用 ignoreVCSIgnored() 方法,重複使用這些規則從結果中排除檔案和目錄
1 2
// excludes files/directories matching the .gitignore patterns
$finder->ignoreVCSIgnored(true);
目錄的規則始終覆蓋其父目錄的規則。
注意
Git 從儲存庫根目錄開始尋找 .gitignore
檔案。Symfony 的 Finder 行為有所不同,它從用於搜尋檔案/目錄的目錄開始尋找 .gitignore
檔案。為了與 Git 行為保持一致,您應該從 Git 儲存庫根目錄明確地進行搜尋。
檔案名稱
使用 name() 方法依名稱尋找檔案
1
$finder->files()->name('*.php');
name()
方法接受 glob、字串、正則表達式或 glob、字串或正則表達式的陣列
1
$finder->files()->name('/\.php$/');
可以透過鏈式調用或傳遞陣列來定義多個檔案名稱
1 2 3 4
$finder->files()->name('*.php')->name('*.twig');
// same as above
$finder->files()->name(['*.php', '*.twig']);
notName()
方法排除符合模式的檔案
1
$finder->files()->notName('*.rb');
可以透過鏈式調用或傳遞陣列來排除多個檔案名稱
1 2 3 4
$finder->files()->notName('*.rb')->notName('*.py');
// same as above
$finder->files()->notName(['*.rb', '*.py']);
檔案內容
使用 contains() 方法依內容尋找檔案
1
$finder->files()->contains('lorem ipsum');
contains()
方法接受字串或正則表達式
1
$finder->files()->contains('/lorem\s+ipsum$/i');
notContains()
方法排除包含給定模式的檔案
1
$finder->files()->notContains('dolor sit amet');
路徑
使用 path() 方法依路徑尋找檔案和目錄
1 2 3 4
// matches files that contain "data" anywhere in their paths (files or directories)
$finder->path('data');
// for example this will match data/*.xml and data.xml if they exist
$finder->path('data')->name('*.xml');
在所有平台上(包括 Windows),使用正斜線 (即 /
) 作為目錄分隔符號。此組件會在內部進行必要的轉換。
path()
方法接受字串、正則表達式或字串或正則表達式的陣列
1 2
$finder->path('foo/bar');
$finder->path('/^foo\/bar/');
可以透過鏈式調用或傳遞陣列來定義多個路徑
1 2 3 4
$finder->path('data')->path('foo/bar');
// same as above
$finder->path(['data', 'foo/bar']);
在內部,字串會透過跳脫斜線並添加分隔符號來轉換為正則表達式
原始給定字串 | 使用的正則表達式 |
---|---|
dirname |
/dirname/ |
a/b/c |
/a\/b\/c/ |
notPath() 方法依路徑排除檔案
1
$finder->notPath('other/dir');
可以透過鏈式調用或傳遞陣列來排除多個路徑
1 2 3 4
$finder->notPath('first/dir')->notPath('other/dir');
// same as above
$finder->notPath(['first/dir', 'other/dir']);
檔案大小
使用 size() 方法依大小尋找檔案
1
$finder->files()->size('< 1.5K');
透過鏈式調用或傳遞陣列,依大小範圍進行限制
1 2 3 4
$finder->files()->size('>= 1K')->size('<= 2K');
// same as above
$finder->files()->size(['>= 1K', '<= 2K']);
比較運算子可以是下列任一項:>
、>=
、<
、<=
、==
、!=
。
目標值可以使用千位元組 (k
、ki
)、百萬位元組 (m
、mi
) 或十億位元組 (g
、gi
) 的量級。帶有 i
後綴的單位使用適當的 2**n
版本,符合 IEC 標準。
檔案日期
使用 date() 方法依上次修改日期尋找檔案
1
$finder->date('since yesterday');
透過鏈式調用或傳遞陣列,依日期範圍進行限制
1 2 3 4
$finder->date('>= 2018-01-01')->date('<= 2018-12-31');
// same as above
$finder->date(['>= 2018-01-01', '<= 2018-12-31']);
比較運算子可以是下列任一項:>
、>=
、<
、<=
、==
。您也可以使用 since
或 after
作為 >
的別名,以及使用 until
或 before
作為 <
的別名。
目標值可以是 strtotime 支援的任何日期。
目錄深度
預設情況下,Finder 會遞迴地遍歷目錄。使用 depth() 限制遍歷深度
1 2 3
// this will only consider files/directories which are direct children
$finder->depth('== 0');
$finder->depth('< 3');
透過鏈式調用或傳遞陣列,依深度範圍進行限制
1 2 3 4
$finder->depth('> 2')->depth('< 5');
// same as above
$finder->depth(['> 2', '< 5']);
自訂篩選
若要使用您自己的策略篩選結果,請使用 filter()
1 2 3 4 5 6 7 8
$filter = function (\SplFileInfo $file)
{
if (strlen($file) > 10) {
return false;
}
};
$finder->files()->filter($filter);
filter()
方法接受 Closure 作為引數。對於每個符合條件的檔案,都會使用該檔案(作為 SplFileInfo 實例)來調用它。如果 Closure 傳回 false
,則該檔案會從結果集中排除。
filter()
方法包含第二個可選引數,用於修剪目錄。如果設定為 true
,此方法會完全跳過排除的目錄,而不是遍歷整個檔案/目錄結構並稍後排除它們。當使用 Closure 時,針對您想要修剪的目錄傳回 false
。
提早修剪目錄可以顯著提升效能,具體取決於檔案/目錄階層的複雜性和排除目錄的數量。
排序結果
依名稱、副檔名、大小或類型排序結果(目錄優先,然後是檔案)
1 2 3 4 5
$finder->sortByName();
$finder->sortByCaseInsensitiveName();
$finder->sortByExtension();
$finder->sortBySize();
$finder->sortByType();
提示
預設情況下,sortByName()
方法使用 strcmp PHP 函數 (例如 file1.txt
、file10.txt
、file2.txt
)。傳遞 true
作為其引數,以改用 PHP 的自然排序演算法 (例如 file1.txt
、file2.txt
、file10.txt
)。
sortByCaseInsensitiveName()
方法使用不區分大小寫的 strcasecmp PHP 函數。傳遞 true
作為其引數,以改用 PHP 的不區分大小寫自然排序演算法 (即 strnatcasecmp PHP 函數)
依上次存取、變更或修改時間排序檔案和目錄
1 2 3 4 5
$finder->sortByAccessedTime();
$finder->sortByChangedTime();
$finder->sortByModifiedTime();
您也可以使用 sort()
方法定義自己的排序演算法
1 2 3
$finder->sort(function (\SplFileInfo $a, \SplFileInfo $b): int {
return strcmp($a->getRealPath(), $b->getRealPath());
});
您可以使用 reverseSorting()
方法反轉任何排序
1 2
// results will be sorted "Z to A" instead of the default "A to Z"
$finder->sortByName()->reverseSorting();
注意
請注意,sort*
方法需要取得所有符合條件的元素才能執行其工作。對於大型迭代器,這會很慢。
將結果轉換為陣列
Finder 實例是 IteratorAggregate PHP 類別。因此,除了使用 foreach
迭代 Finder 結果之外,您也可以使用 iterator_to_array 函數將其轉換為陣列,或使用 iterator_count 取得項目數量。
如果您多次調用 in() 方法以搜尋多個位置,請將 false
作為第二個參數傳遞給 iterator_to_array 以避免問題(會為每個位置建立單獨的迭代器,如果您沒有將 false
傳遞給 iterator_to_array,則會使用結果集的鍵,其中某些鍵可能會重複且其值會被覆寫)。
讀取傳回檔案的內容
可以使用 getContents() 讀取傳回檔案的內容
1 2 3 4 5 6 7 8 9 10
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()->in(__DIR__);
foreach ($finder as $file) {
$contents = $file->getContents();
// ...
}