PHP提供了完善的操作文件与目录机制,工程师需要掌握在后台PHP中管理文件的能力。
本函数返回的是该目录所在的磁盘分区的总大小,因此在给出同一个磁盘分区的不同目录作为参数所得到的结果完全相同。
参数是一个目录的字符串。该函数将根据相应的文件系统或磁盘分区返回可用的字节数。
/** * 获取有单位的大小 * @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(‘.‘));
取得指定文件的大小。
$filename = ‘somefile.txt‘;echo $filename . ‘: ‘ . filesize($filename) . ‘ bytes‘;
打开文件或者 URL。如果打开的是URL需要保证PHP.INI配置项allow_url_fopen
开启。
在操作二进制文件时如果没有指定 ‘b‘ 标记,可能会碰到一些奇怪的问题,包括坏掉的图片文件以及关于 \r\n 字符的奇怪问题。
mode | 说明 |
---|---|
‘r‘ | 只读方式打开,将文件指针指向文件头。 |
‘r+‘ | 读写方式打开,将文件指针指向文件头。 |
‘w‘ | 写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。 |
‘w+‘ | 读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。 |
‘a‘ | 写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。 |
‘a+‘ | 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。 |
‘x‘ | 创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。 |
‘x+‘ | 创建并以读写方式打开,其他的行为和 ‘x‘ 一样。 |
返回所读取的字符串, 或者在失败时返回 FALSE。
$filename = ‘a.txt‘;$handle = fopen($filename,‘r‘);echo fread($handle,filesize($filename));
在文件指针中定位,注意移动到 EOF 之后的位置不算错误。
$filename = ‘a.txt‘;//a.txt内容为 abc$handle = fopen($filename, ‘r+‘);fseek($handle, 1);//移动指针后读取为bcecho fread($handle, filesize($filename));
写入文件,返回写入的字符数,出现错误时则返回 FALSE 。
在区分二进制文件和文本文件的系统上(如 Windows) 打开文件时,fopen() 函数的 mode 参数要加上 ‘b‘。
$handle = fopen(‘xj.txt‘,‘r+‘);fwrite($handle,‘aa‘);fseek($handle,0);echo fread($handle,999);
fclose — 关闭一个已打开的文件指针
$handle = fopen(‘somefile.txt‘, ‘r‘);fclose($handle);
测试文件指针是否到了文件结束的位置
$handle = fopen(‘xj.txt‘,‘rb‘);while(!feof($handle)){ echo fread($handle,1);}
读取一个字符
$handle = fopen(‘xj.txt‘,‘rb‘);while($c = fgetc($handle)) echo $c;
读取一行内容
$handle = fopen(‘xj.txt‘,‘rb‘);while($c = fgets($handle)) echo $c;
从文件指针中读取一行并过滤掉 HTML 标记。
参数分别表示:资源对象、读取数量、允许标签。
$handle = fopen(‘xj.html‘,‘rb‘);while(!feof($handle)){ echo fgetss($handle,20,‘<h1><title>‘);}
从文件指针中读入一行并解析 CSV 字段。
$handle = fopen(‘user.csv‘,‘rb‘);$users = fgetcsv($handle,0,‘,‘);print_r($users);
读取文件所有内容
<?phpheader(‘Content-type:image/jpeg‘);readfile(‘user.jpeg‘);
锁定文件操作,如果使用flock
锁定文件,必须保证在所有使用文件地方执行 flock
才有意义。如果过早的系统因为不支持锁定操作,函数执行将没有效果如FAT系统。
锁定方式 | 说明 |
---|---|
LOCK_SH | 取得共享锁定(读取的程序) |
LOCK_EX | 取得独占锁定(写入的程序) |
LOCK_UN | 释放锁定(无论共享或独占) |
LOCK_NB | 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合使用。(Windows 系统上还不支持) |
1.php 文件内容:
<?php$handle = fopen(‘xj.txt‘,‘rb‘);$stat = flock($handle,LOCK_SH);sleep(5);echo fgetss($handle);flock($handle,LOCK_UN);
2.php
<?php$handle = fopen(‘xj.txt‘,‘rb‘);$stat = flock($handle,LOCK_SH);echo fgetss($handle);flock($handle,LOCK_UN);
读锁不能写入文件可以读取文件,并不会阻塞。
1.php 文件内容:
<?php$handle = fopen(‘xj.txt‘,‘rb‘);$stat = flock($handle,LOCK_EX);sleep(5);echo fgetss($handle);flock($handle,LOCK_UN);
2.php
<?php$handle = fopen(‘xj.txt‘,‘rb‘);$stat = flock($handle,LOCK_SH);echo fgetss($handle);flock($handle,LOCK_UN);
写锁为独占,所以读取文件也会阻塞,前一个文件执行完后才可以执行第二个。
1.php
<?php$handle = fopen(‘xj.txt‘,‘ab‘);$stat = flock($handle,LOCK_EX);sleep(5);echo fgetss($handle);flock($handle,LOCK_UN);
2.php
<?php$handle = fopen(‘xj.txt‘,‘ab‘);$stat = flock($handle,LOCK_SH | LOCK_NB,$wouldblock);if($stat){ $d = fwrite($handle,‘aoxiangjun.com‘); echo fgetss($handle);}else{ echo ‘file is locked‘;}flock($handle,LOCK_UN);
判断给定的文件名是否可写
<?php$filename = ‘test.txt‘;if (is_writable($filename)) { echo ‘The file is writable‘;} else { echo ‘The file is not writable‘;}
判断给定文件名是否可读
<?php$filename = ‘test.txt‘;if (is_readable($filename)) { echo ‘The file is readable‘;} else { echo ‘The file is not readable‘;}
检查文件或目录是否存在
<?php$filename = ‘/path/to/foo.txt‘;if (file_exists($filename)) { echo "The file $filename exists";} else { echo "The file $filename does not exist";}
判断给定文件名是否为一个正常的文件。
判断给定文件名是否是一个目录。
取得指定文件的大小,返回文件大小的字节数。
echo filesize(‘xj.txt‘);
将一个字符串写入文件。
参数 | 说明 |
---|---|
参数一 | 文件名 |
参数二 | 写入的字符串 |
参数三 | FILE_APPEND:如果文件 filename 已经存在,追加数据而不是覆盖。 LOCK_EX:在写入时获得一个独占锁。 |
将整个文件读入一个字符串,如果打开远程文件需要开启php.ini中的 allow_url_fopen
选项。
本函数返回文件中的数据块上次被写入的时间,也就是说,文件的内容上次被修改的时间。
下面是缓存文件的操作代码,实际开发中的缓存控制还要注意很多细节,下面是核心思路代码。
<?php//缓存文件存在并且没有过期时使用缓存文件if (is_file(‘1.cache.php‘) && filemtime(‘1.cache.php‘) > (time() - 10)) { include ‘1.cache.php‘;} else { //开启缓存区并保存解析数据到缓存文件 ob_start(); include ‘1.blade.php‘; $content = ob_get_clean(); echo $content; file_put_contents(‘1.cache.php‘, $content);}
输出或返回一个变量的字符串表示。
下面是将数组保存到文件中的代码,并支持include 获取数组数据。
<?php$user = [ [‘name‘=>‘向军大叔‘], [‘name‘=>‘小明‘]];$content =var_export($user,true);file_put_contents(‘users.php‘,‘<?php return ‘.$content.‘;‘);
返回路径中的文件名部分
echo basename(__FILE__);
返回路径中的目录部分
echo dirname(__FILE__);
支持递归的目录创建,参数分别是:目录、权限位、递归创建
mkdir(‘a/b/c‘,0755,true);
删除指定的目录,该目录必须是空的,而且要有相应的权限。
rmdir(‘views‘);
重命名一个文件或目录,也可以进行文件移动。
// 将1.html更名为a.htmlrename(‘1.html‘,‘a.html‘);//移动文件1.html到目录houdunren中rename(‘1.html‘,‘houdunren/1.html‘);
复制文件
//复制1.blade.php到目录f中copy(‘1.blade.php‘,‘f/1.blade.php‘);
获取文件所有目录。
获取文件的完整路径,包含文件名。
目录分隔符,在 Windows 中,斜线(/)和反斜线(\)都可以用作目录分隔符,但是在linux上使用/
,此常量会自动根据系统设置为合适的分隔符。
opendir 函数类似于 fopen 操作方式,可能获取目录指针读取目录,下面是操作示例。
$handle = opendir(‘../php‘);while (false!==($file = readdir($handle))) { if (!in_array($file, [‘.‘,‘..‘])) { echo filetype($file)."\t".$file.‘<br/>‘; }}closedir($handle);
列出指定路径中的文件和目录。
foreach (scandir(‘../php‘) as $file) { if (!in_array($file, [‘.‘,‘..‘])) { echo filetype($file)."\t\t".$file.‘<hr/>‘; }}
寻找与模式匹配的文件路径。
参数顺序为:参数一文件路径,参数二选项标记
下面是常用选项标记
选项 | 说明 |
---|---|
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);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(‘/home/vagrant‘)/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(‘../php2‘);
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);}