Finder 组件
Finder 组件根据不同的标准(名称、文件大小、修改时间等)通过直观的流畅接口查找文件和目录。
安装
1
$ composer require symfony/finder
注意
如果您在 Symfony 应用程序之外安装此组件,则必须在代码中 require 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 风格协议的 PHP 封装器 (ftp://
, zlib://
, 等等) 的 URL
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
,则此方法完全跳过排除的目录,而不是遍历整个文件/目录结构并在稍后排除它们。当使用闭包时,对于您要修剪的目录,返回 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();
// ...
}