Filesystem 组件
Filesystem 组件提供了平台无关的实用工具,用于文件系统操作和文件/目录路径操作。
安装
1
$ composer require symfony/filesystem
注意
如果你在 Symfony 应用程序之外安装此组件,你必须在你的代码中 require vendor/autoload.php
文件,以启用 Composer 提供的类自动加载机制。阅读 这篇文章 以获取更多详细信息。
用法
该组件包含两个主要的类,分别名为 Filesystem 和 Path
1 2 3 4 5 6 7 8 9 10 11 12 13
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;
$filesystem = new Filesystem();
try {
$filesystem->mkdir(
Path::normalize(sys_get_temp_dir().'/'.random_int(0, 1000)),
);
} catch (IOExceptionInterface $exception) {
echo "An error occurred while creating your directory at ".$exception->getPath();
}
Filesystem 实用工具
mkdir
mkdir() 递归地创建目录。在 POSIX 文件系统上,目录默认以模式值 0777
创建。你可以使用第二个参数来设置你自己的模式
1
$filesystem->mkdir('/tmp/photos', 0700);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
注意
此函数会忽略已存在的目录。
exists
exists() 检查一个或多个文件或目录是否存在,如果任何一个文件或目录缺失,则返回 false
1 2 3 4 5 6
// if this absolute directory exists, returns true
$filesystem->exists('/tmp/photos');
// if rabbit.jpg exists and bottle.png does not exist, returns false
// non-absolute paths are relative to the directory where the running PHP script is stored
$filesystem->exists(['rabbit.jpg', 'bottle.png']);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
copy
copy() 创建单个文件的副本(使用 mirror() 复制目录)。如果目标已存在,则仅当源修改日期晚于目标日期时才复制文件。此行为可以通过第三个布尔参数覆盖
1 2 3 4 5
// works only if image-ICC has been modified after image.jpg
$filesystem->copy('image-ICC.jpg', 'image.jpg');
// image.jpg will be overridden
$filesystem->copy('image-ICC.jpg', 'image.jpg', true);
touch
touch() 设置文件的访问和修改时间。默认使用当前时间。你可以使用第二个参数设置你自己的时间。第三个参数是访问时间
1 2 3 4 5 6
// sets modification time to the current timestamp
$filesystem->touch('file.txt');
// sets modification time 10 seconds in the future
$filesystem->touch('file.txt', time() + 10);
// sets access time 10 seconds in the past
$filesystem->touch('file.txt', time(), time() - 10);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
chown
chown() 更改文件的所有者。第三个参数是布尔递归选项
1 2 3 4
// sets the owner of the lolcat video to www-data
$filesystem->chown('lolcat.mp4', 'www-data');
// changes the owner of the video directory recursively
$filesystem->chown('/video', 'www-data', true);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
chgrp
chgrp() 更改文件的组。第三个参数是布尔递归选项
1 2 3 4
// sets the group of the lolcat video to nginx
$filesystem->chgrp('lolcat.mp4', 'nginx');
// changes the group of the video directory recursively
$filesystem->chgrp('/video', 'nginx', true);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
chmod
chmod() 更改文件的模式或权限。第四个参数是布尔递归选项
1 2 3 4
// sets the mode of the video to 0600
$filesystem->chmod('video.ogg', 0600);
// changes the mode of the src directory recursively
$filesystem->chmod('src', 0700, 0000, true);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
remove
remove() 删除文件、目录和符号链接
1
$filesystem->remove(['symlink', '/path/to/directory', 'activity.log']);
注意
你可以传递一个数组或任何 Traversable 对象作为第一个参数。
rename
rename() 更改单个文件或目录的名称
1 2 3 4 5 6
// renames a file
$filesystem->rename('/tmp/processed_video.ogg', '/path/to/store/video_647.ogg');
// renames a directory
$filesystem->rename('/tmp/files', '/path/to/store/files');
// if the target already exists, a third boolean argument is available to overwrite.
$filesystem->rename('/tmp/processed_video2.ogg', '/path/to/store/video_647.ogg', true);
symlink
symlink() 从目标创建到目的地的符号链接。如果文件系统不支持符号链接,则可以使用第三个布尔参数
1 2 3 4 5
// creates a symbolic link
$filesystem->symlink('/path/to/source', '/path/to/destination');
// duplicates the source directory if the filesystem
// does not support symbolic links
$filesystem->symlink('/path/to/source', '/path/to/destination', true);
readlink
readlink() 读取链接目标。
Filesystem 组件提供的 readlink() 方法在所有操作系统上的行为方式都相同(与 PHP 的 readlink 函数不同)
1 2 3 4 5
// returns the next direct target of the link without considering the existence of the target
$filesystem->readlink('/path/to/link');
// returns its absolute fully resolved final version of the target (if there are nested links, they are resolved)
$filesystem->readlink('/path/to/link', true);
其行为如下:
当
$canonicalize
为false
时:- 如果
$path
不存在或不是链接,则返回null
。 - 如果
$path
是链接,它将返回链接的下一个直接目标,而不考虑目标是否存在。
- 如果
当
$canonicalize
为true
时:- 如果
$path
不存在,则返回 null。 - 如果
$path
存在,则返回其绝对完全解析的最终版本。
- 如果
注意
如果你希望在不检查路径是否存在的情况下规范化路径,则可以使用 canonicalize() 方法。
makePathRelative
makePathRelative() 接受两个绝对路径,并返回从第二个路径到第一个路径的相对路径
1 2 3 4 5 6 7
// returns '../'
$filesystem->makePathRelative(
'/var/lib/symfony/src/Symfony/',
'/var/lib/symfony/src/Symfony/Component'
);
// returns 'videos/'
$filesystem->makePathRelative('/tmp/videos', '/tmp');
mirror
mirror() 将源目录的所有内容复制到目标目录中(使用 copy() 方法复制单个文件)
1
$filesystem->mirror('/path/to/source', '/path/to/target');
isAbsolutePath
isAbsolutePath() 如果给定的路径是绝对路径,则返回 true
,否则返回 false
1 2 3 4 5 6 7 8
// returns true
$filesystem->isAbsolutePath('/tmp');
// returns true
$filesystem->isAbsolutePath('c:\\Windows');
// returns false
$filesystem->isAbsolutePath('tmp');
// returns false
$filesystem->isAbsolutePath('../dir');
tempnam
tempnam() 创建一个带有唯一文件名的临时文件,并返回其路径,或者在失败时抛出异常
1 2 3 4
// returns a path like : /tmp/prefix_wyjgtF
$filesystem->tempnam('/tmp', 'prefix_');
// returns a path like : /tmp/prefix_wyjgtF.png
$filesystem->tempnam('/tmp', 'prefix_', '.png');
dumpFile
dumpFile() 将给定的内容保存到一个文件中(如果文件及其目录不存在,则创建它们)。它以原子方式执行此操作:它首先写入一个临时文件,然后在完成后将其移动到新的文件位置。这意味着用户将始终看到完整的旧文件或完整的新文件(但永远不会看到部分写入的文件)
1
$filesystem->dumpFile('file.txt', 'Hello World');
现在 file.txt
文件包含 Hello World
。
appendToFile
appendToFile() 在某些文件的末尾添加新内容
1 2 3
$filesystem->appendToFile('logs.txt', 'Email sent to [email protected]');
// the third argument tells whether the file should be locked when writing to it
$filesystem->appendToFile('logs.txt', 'Email sent to [email protected]', true);
如果文件或其包含目录不存在,此方法会在追加内容之前创建它们。
readFile
7.1
readFile()
方法在 Symfony 7.1 中引入。
readFile() 以字符串形式返回文件的所有内容。与 PHP 的 file_get_contents 函数不同,当给定的文件路径不可读以及传递目录路径而不是文件时,它会抛出异常
1
$contents = $filesystem->readFile('/some/path/to/file.txt');
现在 $contents
变量存储了 file.txt
文件的所有内容。
路径操作实用工具
处理文件路径通常会遇到一些困难:
- 平台差异:文件路径在不同的平台上看起来不同。UNIX 文件路径以斜杠 (“/”) 开头,而 Windows 文件路径以系统驱动器 (“C:”) 开头。UNIX 使用正斜杠,而 Windows 默认使用反斜杠。
- 绝对/相对路径:Web 应用程序经常需要处理绝对路径和相对路径。正确地将一种路径转换为另一种路径是棘手且重复的。
Path 提供了实用方法来解决这些问题。
规范化
返回与给定路径等效的最短路径名。它迭代地应用以下规则,直到无法进行进一步处理:
- “.” 段被移除;
- “..” 段被解析;
- 反斜杠 (“\”) 被转换为正斜杠 (“/”);
- 根路径 (“/” 和 “C:/”) 始终以斜杠结尾;
- 非根路径永远不会以斜杠结尾;
- 方案(例如 “phar://”)被保留;
- 将
~
替换为用户的 home 目录。
你可以使用 canonicalize() 规范化路径
1 2
echo Path::canonicalize('/var/www/vhost/webmozart/../config.ini');
// => /var/www/vhost/config.ini
你可以将绝对路径和相对路径传递给 canonicalize() 方法。当传递相对路径时,路径开头的 “..” 段会被保留
1 2
echo Path::canonicalize('../uploads/../config/config.yaml');
// => ../config/config.yaml
格式错误的路径将原样返回
1 2
echo Path::canonicalize('C:Programs/PHP/php.ini');
// => C:Programs/PHP/php.ini
转换绝对/相对路径
绝对/相对路径可以使用方法 makeAbsolute() 和 makeRelative() 进行转换。
makeAbsolute() 方法需要一个相对路径和一个基础路径,以该基础路径为基础来解析相对路径
1 2
echo Path::makeAbsolute('config/config.yaml', '/var/www/project');
// => /var/www/project/config/config.yaml
如果在第一个参数中传递了绝对路径,则绝对路径将原样返回
1 2
echo Path::makeAbsolute('/usr/share/lib/config.ini', '/var/www/project');
// => /usr/share/lib/config.ini
该方法会解析 “..” 段(如果存在任何段)
1 2
echo Path::makeAbsolute('../config/config.yaml', '/var/www/project/uploads');
// => /var/www/project/config/config.yaml
如果你希望能够同时接受相对路径(例如,相对于项目根目录的相对路径)和绝对路径,则此方法非常有用。
makeRelative() 是 makeAbsolute() 的逆操作
1 2
echo Path::makeRelative('/var/www/project/config/config.yaml', '/var/www/project');
// => config/config.yaml
如果路径不在基础路径内,则该方法将根据需要前置 “..” 段
1 2
echo Path::makeRelative('/var/www/project/config/config.yaml', '/var/www/project/uploads');
// => ../config/config.yaml
使用 isAbsolute() 和 isRelative() 检查路径是绝对路径还是相对路径
1 2
Path::isAbsolute('C:\Programs\PHP\php.ini')
// => true
所有这四个方法都在内部规范化传递的路径。
查找最长公共基础路径
当你在文件系统中存储绝对文件路径时,这会导致大量重复的信息
1 2 3 4 5 6 7
return [
'/var/www/vhosts/project/httpdocs/config/config.yaml',
'/var/www/vhosts/project/httpdocs/config/routing.yaml',
'/var/www/vhosts/project/httpdocs/config/services.yaml',
'/var/www/vhosts/project/httpdocs/images/banana.gif',
'/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif',
];
特别是在存储大量路径时,重复信息的数量非常明显。您可以使用 getLongestCommonBasePath() 来检查路径列表中是否存在公共基础路径
1 2 3 4 5 6 7 8
$basePath = Path::getLongestCommonBasePath(
'/var/www/vhosts/project/httpdocs/config/config.yaml',
'/var/www/vhosts/project/httpdocs/config/routing.yaml',
'/var/www/vhosts/project/httpdocs/config/services.yaml',
'/var/www/vhosts/project/httpdocs/images/banana.gif',
'/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif'
);
// => /var/www/vhosts/project/httpdocs
使用此公共基础路径来缩短存储的路径
1 2 3 4 5 6 7
return [
$basePath.'/config/config.yaml',
$basePath.'/config/routing.yaml',
$basePath.'/config/services.yaml',
$basePath.'/images/banana.gif',
$basePath.'/uploads/images/nicer-banana.gif',
];
getLongestCommonBasePath() 始终返回规范路径。
使用 isBasePath() 来测试一个路径是否是另一个路径的基础路径
1 2 3 4 5 6 7 8
Path::isBasePath("/var/www", "/var/www/project");
// => true
Path::isBasePath("/var/www", "/var/www/project/..");
// => true
Path::isBasePath("/var/www", "/var/www/project/../..");
// => false
查找目录/根目录
PHP 提供了函数 dirname 来获取文件路径的目录路径。此方法有一些怪癖
dirname()
在 UNIX 上不接受反斜杠dirname("C:/Programs")
返回 "C:",而不是 "C:/"dirname("C:/")
返回 ".",而不是 "C:/"dirname("C:")
返回 ".",而不是 "C:/"dirname("Programs")
返回 ".",而不是 ""dirname()
不会对结果进行规范化
getDirectory() 修复了这些缺点
1 2
echo Path::getDirectory("C:\Programs");
// => C:/
此外,您可以使用 getRoot() 来获取路径的根目录
1 2 3 4 5
echo Path::getRoot("/etc/apache2/sites-available");
// => /
echo Path::getRoot("C:\Programs\Apache\Config");
// => C:/
错误处理
每当发生错误时,都会抛出一个实现了 ExceptionInterface 或 IOExceptionInterface 的异常。
注意
如果目录创建失败,则会抛出 IOException 异常。