文件与目录
======【常见函数】======
获取磁盘大小:disk_total_space
本函数返回的是该目录所在的磁盘分区的总大小,因此在给出同一个磁盘分区的不同目录作为参数所得到的结果完全相同。
echo disk_total_space('.'); // 132678414336,单位:Byte(字节)获取可用空间大小:disk_free_space
参数是一个目录的字符串。该函数将根据相应的文件系统或磁盘分区返回可用的字节数。
echo disk_free_space('.'); // 50684268544,单位:Byte(字节)单位转换(磁盘大小,可用空间)
/**
* 获取有单位的大小
* @param int $total 大小单位字节
* @return string|null
*/
function space_total(int $total): ?string
{
$config = [3 => 'GB', 2 => 'MB', 1 => 'KB'];
foreach ($config as $num => $unit) {
if ($total > pow(1024, $num)) {
return round($total / pow(1024, $num)) . $unit;
}
}
return '0KB';
}
echo space_total(disk_total_space('.')); // 124GB获取指定文件大小:filesize
取得指定文件的大小,返回文件大小的字节数。
$filename = 'index.php';
echo $filename . ': ' . filesize($filename) . ' bytes'; // index.php: 87 bytes转换文件大小的单位:
function getsize($size, $format = 'kb')
{
$p = 0;
if ($format == 'kb') {
$p = 1;
} elseif ($format == 'mb') {
$p = 2;
} elseif ($format == 'gb') {
$p = 3;
}
$size /= pow(1024, $p);
return number_format($size, 3);
}打开文件或者URL:fopen
打开文件或者 URL。如果打开的是URL需要保证php.ini配置项allow_url_fopen开启。
在操作二进制文件时如果没有指定 'b' 标记,可能会碰到一些奇怪的问题,包括坏掉的图片文件以及关于 \r\n 字符的奇怪问题。
| mode | 说明 |
|---|---|
| 'r' | 只读方式打开,将文件指针指向文件头。 |
| 'r+' | 读写方式打开,将文件指针指向文件头。 |
| 'w' | 写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。 |
| 'w+' | 读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。 |
| 'a' | 写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。 |
| 'a+' | 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。 |
| 'x' | 创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。 |
| 'x+' | 创建并以读写方式打开,其他的行为和 'x' 一样。 |
读取文件内容:fread
返回所读取的字符串, 或者在失败时返回 FALSE。
$filename = 'foo.txt'; // 内容:Hello World
$handle = fopen($filename, 'r');
// var_dump($handle); // resource(3) of type (stream)
// echo filesize($filename); // 11
// var_dump(fread($handle, 5)); // string(5) "Hello"
var_dump(fread($handle,2)); // string(2) "He"
echo '<br>';
var_dump(fread($handle, filesize($filename))); // string(9) "llo World"
var_dump(fread($handle, filesize($filename))); // string(11) "Hello World"
var_dump(fread($handle, filesize($filename))); // string(0) "",因为上面指针读完数据了指针定位:fseek
在文件指针中定位,注意移动到 EOF 之后的位置不算错误。
$filename = 'foo.txt'; // 内容:Hello World
$handle = fopen($filename, 'r');
fseek($handle, 0);
var_dump(fread($handle, filesize($filename))); // string(11) "Hello World"写入文件:fwrite
写入文件,返回写入的字符数,出现错误时则返回 FALSE 。
在区分二进制文件和文本文件的系统上(如 Windows) 打开文件时,fopen()函数的 mode 参数要加上 'b'。
- r模式
$filename = 'foo.txt'; // 内容:Hello World
$handle = fopen($filename, 'r+'); // 如果是插入二进制数据(音视频),使用r+b
fseek($handle, filesize($filename)); // 将光标移到内容最后面,否则默认最开始位置,会覆盖原有内容
$string = ' !';
fwrite($handle, $string);
fseek($handle, 0);
echo fread($handle, filesize($filename) + strlen($string)); // Hello World !- w模式
$handle = fopen('foo2.txt', 'w+b');
fwrite($handle, 'hello');
fseek($handle, 0);
echo fread($handle, 999); // hello- a模式
$handle = fopen('foo2.txt', 'a+');
fwrite($handle, '世界上最好的语言');
fseek($handle, 0);
echo fread($handle, 9999); // 世界上最好的语言- x模式
$handle = fopen('foo2.txt', 'x+');
fwrite($handle, '世界上最好的语言');
fseek($handle, 0);
echo fread($handle, 9999); // 世界上最好的语言- 读取二进制文件
// 读取并显示一张图片
header('Content-type:image/png');
$filename = 'A07.jpg';
$handle = fopen($filename, 'rb');
echo fread($handle, filesize($filename));
// 读取并新增加一张图片
$png = fopen('new.png', 'x');
fwrite($png, fread($handle, filesize($filename)));- 读取网络上的文件
$filename = 'http://s.siushin.com';
$handle = fopen($filename, 'r');
echo fread($handle, 99999);
// 正则获取html中指定内容
preg_match('/"code":(.*),/isU', fread($handle, 99999), $matchs);
echo $matchs[1]; // 400关闭文件指针:fclose
关闭一个已打开的文件指针
$handle = fopen('foo.txt', 'r');
fclose($handle); // 注意判断文件是否存在,否则抛出异常测试文件指针是否在最后面:feof
测试文件指针是否到了文件结束的位置
$handle = fopen('foo.txt', 'rb'); // 内容:世界上最好的语言
while (!feof($handle)) {
echo fread($handle, 1);
}
// 输出:世界上最好的语言读取一个字符:fgetc
$handle = fopen('foo.txt', 'rb'); // 内容:世界上最好的语言
while ($c = fgetc($handle))
echo $c;
// 输出:世界上最好的语言读取一行字符:fgets
$handle = fopen('foo.txt', 'rb');
while ($c = fgets($handle)) // fgets ($stream, $length = null)
echo $c;读取一行并过滤掉 HTML 标记:fgetss(7.3弃用)
从文件指针中读取一行并过滤掉 HTML 标记。
参数分别表示:资源对象、读取数量、允许标签。
// index.html内容:
<<<eof
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World</title>
</head>
<body>
测试网页
</body>
</html>
eof;
$filename = 'index.html'; // 也可以是url,此处方便演示,使用本地文件
$handle = fopen($filename, 'rb');
error_reporting(0);
while (!feof($handle)) {
echo fgetss($handle, 99999, '<head><body>'); // 参数分别表示:资源对象、读取数量、允许标签
}文件读入一行解析csv:fgetcsv
从文件指针中读入一行并解析 CSV 字段。
$handle = fopen('user.csv', 'rb');
$users = fgetcsv($handle, 0, ',');
print_r($users); // Array ( [0] => sina.com )读取文件所有内容:readfile
header('Content-type:image/png');
readfile('A07.jpg');锁定文件操作:flock
锁定文件操作,如果使用 flock 锁定文件,必须保证在所有使用文件地方执行 flock 才有意义。如果过早的系统因为不支持锁定操作,函数执行将没有效果如FAT系统。
| 锁定方式 | 说明 |
|---|---|
| LOCK_SH | 取得共享锁定(读取的程序) |
| LOCK_EX | 取得独占锁定(写入的程序) |
| LOCK_UN | 释放锁定(无论共享或独占) |
| LOCK_NB | 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合使用。(Windows 系统上还不支持) |
读锁
1.php 文件内容:
$handle = fopen('foo.txt', 'r');
flock($handle, LOCK_SH);
sleep(5);
echo fread($handle, 9999);
fclose($handle);2.php 文件内容:
$handle = fopen('foo.txt', 'rb');
flock($handle, LOCK_SH);
echo fread($handle, 9999);
fclose($handle);读锁不能写入文件可以读取文件,并不会阻塞。
写锁
1.php 文件内容:
$handle = fopen('foo.txt', 'rb');
flock($handle, LOCK_EX);
sleep(3);
echo fread($handle, 9999);
flock($handle, LOCK_UN);
fclose($handle);2.php 文件内容:
$handle = fopen('foo.txt', 'rb');
flock($handle, LOCK_SH);
flock($handle, LOCK_UN); // 低版本,执行完脚本自动解锁;高版本,可能需要手动解锁。
fclose($handle);写锁为独占,所以读取文件也会阻塞,前一个文件执行完后才可以执行第二个。
防止阻塞
1.php 文件内容:
$handle = fopen('foo.txt', 'rb');
flock($handle, LOCK_SH);
sleep(3);
echo fread($handle, 9999);
flock($handle, LOCK_UN);
fclose($handle);2.php 文件内容:
$handle = fopen('foo.txt', 'w');
$status = flock($handle, LOCK_EX | LOCK_NB, $would_block);
if ($status) { // !$would_block效果一样,1:堵塞,0:没有锁
fwrite($handle, 'Hello World');
} else {
echo 'file is locked';
}
flock($handle, LOCK_UN);
fclose($handle);- 使用LOCK_NB当文件被其他请求锁定时,脚本继续向下执行,锁定失败。
- 阻塞时 $wouldblock 为真(1),可以判断是否执行相应代码作为依据
判断文件是否可写:is_writable
判断给定的文件名是否可写
$filename = 'foo.txt';
if (is_writable($filename)) {
echo 'The file is writable';
} else {
echo 'The file is not writable';
}判断文件是否可读:is_readable
判断给定文件名是否可读
$filename = 'foo.txt';
if (is_readable($filename)) {
echo 'The file is readable';
} else {
echo 'The file is not readable';
}判断文件或目录是否存在:file_exists
检查文件或目录是否存在
file_exists不仅可以判断文件是否存在,同时也可以判断目录是否存在
$filename = 'foo.txt';
if (file_exists($filename)) {
echo "The file $filename exists";
} else {
echo "The file $filename does not exist";
}判断是否是文件:is_file
判断给定文件名是否为一个正常的文件。
文件是否可读:is_readable
$filename = './test.txt';
if (is_readable($filename)) {
echo file_get_contents($filename);
}文件是否可写:is_writeable
$filename = './test.txt';
if (is_writeable($filename)) {
file_put_contents($filename, 'test');
}判断是否是目录:is_dir
判断给定文件名是否是一个目录。
文件写入字符串:file_put_contents
将一个字符串写入文件。
| 参数 | 说明 |
|---|---|
| 参数一 | 文件名 |
| 参数二 | 写入的字符串 |
| 参数三 | FILE_APPEND:如果文件 filename 已经存在,追加数据而不是覆盖。LOCK_EX:在写入时获得一个独占锁。 |
$filename = './test.txt';
$data = 'test';
file_put_contents($filename, $data);上例中,$data参数可以是一个一维数组,当$data是数组的时候,会自动的将数组连接起来,相当于$data=implode('', $data);
同样的,PHP也支持类似C语言风格的操作方式,采用fwrite进行文件写入。
$fp = fopen('./test.txt', 'a'); // a:追加写入
fwrite($fp, 'hello' . PHP_EOL);
fwrite($fp, 'world' . PHP_EOL);
fclose($fp);将文件读取成字符串:file_get_content
将整个文件读入一个字符串,如果打开远程文件需要开启php.ini中的 allow_url_fopen 选项。
获得文件的所有者:fileowner
fileowner:获得文件的所有者
获取文件的创建时间:filectime
filectime:获取文件的创建时间
获取文件的修改时间:filemtime
本函数返回文件中的数据块上次被写入的时间,也就是说,文件的内容上次被修改的时间。
下面是缓存文件的操作代码,实际开发中的缓存控制还要注意很多细节,下面是核心思路代码。
//缓存文件存在并且没有过期时使用缓存文件
if (is_file('1.cache.php') && filemtime('1.cache.php') > (time() - 10)) {
include '1.cache.php';
echo 'is cache...';
} else {
//开启缓存区并保存解析数据到缓存文件
ob_start();
include '1.blade.php';
$content = ob_get_clean();
echo $content;
file_put_contents('1.cache.php', $content);
}获取文件的访问时间:fileatime
fileatime:获取文件的访问时间
输出一个变量的字符串表示:var_export
输出或返回一个变量的字符串表示。
下面是将数组保存到文件中的代码,并支持include 获取数组数据。
$user = [
['name' => '张三'],
['name' => '李四']
];
$content = var_export($user, true);
file_put_contents('users.php', "<?php return $content;");返回路径中的文件名部分:basename
echo basename(__FILE__); // index.php返回路径中的目录部分:dirname
echo dirname(__FILE__); // D:\www创建目录:mkdir
支持递归的目录创建,参数分别是:目录、权限位、递归创建
mkdir('a/b/c', 0755, true);删除目录:rmdir
删除指定的目录,该目录必须是空的,而且要有相应的权限。
rmdir('cache');重命名文件或目录:rename
重命名一个文件或目录,也可以进行文件移动。
// 将1.html更名为a.html
rename('1.html', 'a.html');
//移动文件1.html到目录houdunren中
rename('1.html', 'view/1.html');复制文件:copy
// 复制1.blade.php到目录f中
copy('1.blade.php', 'f/1.blade.php');======【常用常量】======
获取文件所有目录:DIR
获取文件的完整路径,包含文件名:FILE
目录分隔符:DIRECTORY_SEPARATOR
目录分隔符,在 Windows 中,斜线(/)和反斜线(\)都可以用作目录分隔符,但是在linux上使用/,此常量会自动根据系统设置为合适的分隔符。
======【目录操作】======
读取目录:opendir
opendir 函数类似于 fopen 操作方式,可能获取目录指针读取目录。
$handle = opendir('.'); // resource(3) of type (stream)
while (false !== ($file = readdir($handle))) {
if (!in_array($file, ['.', '..'])) {
echo filetype($file) . "\t" . $file . '<br/>';
}
}
closedir($handle);列出文件和目录:scandir
列出指定路径中的文件和目录
foreach (scandir('.') as $file) {
if (!in_array($file, ['.', '..'])) {
echo filetype($file) . "\t\t" . $file . '<hr/>';
}
}寻找与匹配文件路径:glob
寻找与模式匹配的文件路径。
参数顺序为:参数一文件路径,参数二选项标记
下面是常用选项标记
| 选项 | 说明 |
|---|---|
| GLOB_MARK | 在每个返回的项目中加一个斜线 |
| GLOB_NOSORT | 按照文件在目录中出现的原始顺序返回(不排序) |
| GLOB_NOCHECK | 如果没有文件匹配则返回用于搜索的模式 |
| GLOB_ERR | 停止并读取错误信息(比如说不可读的目录),默认的情况下忽略所有错误 |
| GLOB_BRACE | 设置多个匹配模式,如:{.php,.txt} |
- 遍历目录
$files = glob('../../*');
print_r($files);- 指定检索文件类型
$files = glob('*.php', GLOB_ERR);- 设置多个匹配模式
$files = glob("{*.php,*.txt}", GLOB_BRACE);
// Array ( [0] => index.php [1] => foo.txt )
print_r($files);目录大小
function dirSize($dir): int
{
$size = 0;
foreach (glob($dir . '/*') as $file) {
$size += is_file($file) ? filesize($file) : dirSize($file);
}
return $size;
}
echo round(dirSize('D:/www/php7') / 1024 / 1024) . 'MB';删除目录
function delDir($dir): bool
{
if (!is_dir($dir)) {
return true;
}
foreach (glob($dir . '/*') as $file) {
is_file($file) ? unlink($file) : delDir($file);
}
return rmdir($dir);
}
delDir('D:/www/php7');复制目录
function copyDir($dir, $to): bool
{
is_dir($to) or mkdir($to, 0755, true);
foreach (glob($dir . '/*') as $file) {
$target = $to . '/' . basename($file);
is_file($file) ? copy($file, $target) : copyDir($file, $target);
}
return true;
}
copyDir('../php', '../php2');移动目录
移动目录分两步执行,第一步是复制目录,第二步是删除目录,所以使用上面两个函数的综合即可以。
function moveDir($dir, $to): bool
{
copyDir($dir, $to);
return delDir($dir);
}