跳到內容

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.txtfile2link (此連結未解析)。folder3link 不會出現在結果中,因為它未被追蹤或解析;
  • 當使用 followLinks() 方法時:file1.txtfile2link (此連結仍然未解析) 和 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']);

比較運算子可以是下列任一項:>>=<<===!=

目標值可以使用千位元組 (kki)、百萬位元組 (mmi) 或十億位元組 (ggi) 的量級。帶有 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']);

比較運算子可以是下列任一項:>>=<<===。您也可以使用 sinceafter 作為 > 的別名,以及使用 untilbefore 作為 < 的別名。

目標值可以是 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.txtfile10.txtfile2.txt)。傳遞 true 作為其引數,以改用 PHP 的自然排序演算法 (例如 file1.txtfile2.txtfile10.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();

    // ...
}
本作品,包含程式碼範例,以 Creative Commons BY-SA 3.0 授權條款發布。
目錄
    版本