PHP提供了完善的操作文件與目錄機(jī)制碍沐。
基礎(chǔ)函數(shù)
disk_total_space
本函數(shù)返回的是該目錄所在的磁盤分區(qū)的總大小,因此在給出同一個(gè)磁盤分區(qū)的不同目錄作為參數(shù)所得到的結(jié)果完全相同雪猪。
disk_free_space
參數(shù)是一個(gè)目錄的字符串绰寞。該函數(shù)將根據(jù)相應(yīng)的文件系統(tǒng)或磁盤分區(qū)返回可用的字節(jié)數(shù)撮竿。
自動(dòng)添加單位
/**
* 獲取有單位的大小
* @param int $total 大小單位字節(jié)
* @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('.'));
filesize
取得指定文件的大小纤泵。
$filename = 'somefile.txt';
echo $filename . ': ' . filesize($filename) . ' bytes';
fopen
打開文件或者 URL骆姐。如果打開的是URL需要保證PHP.INI配置項(xiàng)allow_url_fopen 開啟。
在操作二進(jìn)制文件時(shí)如果沒(méi)有指定 'b' 標(biāo)記捏题,可能會(huì)碰到一些奇怪的問(wèn)題玻褪,包括壞掉的圖片文件以及關(guān)于 \r\n 字符的奇怪問(wèn)題。
mode | 說(shuō)明 |
---|---|
'r' | 只讀方式打開公荧,將文件指針指向文件頭带射。 |
'r+' | 讀寫方式打開,將文件指針指向文件頭循狰。 |
'w' | 寫入方式打開窟社,將文件指針指向文件頭并將文件大小截為零。如果文件不存在則嘗試創(chuàng)建之绪钥。 |
'w+' | 讀寫方式打開桥爽,將文件指針指向文件頭并將文件大小截為零。如果文件不存在則嘗試創(chuàng)建之昧识。 |
'a' | 寫入方式打開,將文件指針指向文件末尾盗扒。如果文件不存在則嘗試創(chuàng)建之跪楞。 |
'a+' | 讀寫方式打開,將文件指針指向文件末尾侣灶。如果文件不存在則嘗試創(chuàng)建之甸祭。 |
'x' | 創(chuàng)建并以寫入方式打開,將文件指針指向文件頭褥影。如果文件已存在池户,則 fopen() 調(diào)用失敗并返回 FALSE,并生成一條 E_WARNING 級(jí)別的錯(cuò)誤信息。如果文件不存在則嘗試創(chuàng)建之校焦。 |
'x+' | 創(chuàng)建并以讀寫方式打開赊抖,其他的行為和 'x' 一樣。 |
fread
返回所讀取的字符串寨典, 或者在失敗時(shí)返回 FALSE氛雪。
$filename = 'a.txt';
$handle = fopen($filename,'r');
echo fread($handle,filesize($filename));
fseek
在文件指針中定位,注意移動(dòng)到 EOF 之后的位置不算錯(cuò)誤耸成。
$filename = 'a.txt';//a.txt內(nèi)容為 abc
$handle = fopen($filename, 'r+');
fseek($handle, 1);
//移動(dòng)指針后讀取為bc
echo fread($handle, filesize($filename));
fwrite
寫入文件报亩,返回寫入的字符數(shù),出現(xiàn)錯(cuò)誤時(shí)則返回 FALSE 弦追。
在區(qū)分二進(jìn)制文件和文本文件的系統(tǒng)上(如 Windows) 打開文件時(shí),fopen() 函數(shù)的 mode 參數(shù)要加上 'b'劲件。
$handle = fopen('pf.txt','r+');
fwrite($handle,'aa');
fseek($handle,0);
echo fread($handle,999);
fclose
fclose — 關(guān)閉一個(gè)已打開的文件指針
$handle = fopen('somefile.txt', 'r');
fclose($handle);
feof
測(cè)試文件指針是否到了文件結(jié)束的位置
$handle = fopen('pf.txt','rb');
while(!feof($handle)){
echo fread($handle,1);
}
fgetc
讀取一個(gè)字符
$handle = fopen('pf.txt','rb');
while($c = fgetc($handle))
echo $c;
fgets
讀取一行內(nèi)容
$handle = fopen('pf.txt','rb');
while($c = fgets($handle))
echo $c;
fgetss
從文件指針中讀取一行并過(guò)濾掉 HTML 標(biāo)記左胞。
參數(shù)分別表示:資源對(duì)象、讀取數(shù)量烤宙、允許標(biāo)簽。
$handle = fopen('pf.html','rb');
while(!feof($handle)){
echo fgetss($handle,20,'<h1><title>');
}
fgetcsv
從文件指針中讀入一行并解析 CSV 字段躺枕。
$handle = fopen('user.csv','rb');
$users = fgetcsv($handle,0,',');
print_r($users);
readfile
讀取文件所有內(nèi)容
<?php
header('Content-type:image/jpeg');
readfile('user.jpeg');
flock
鎖定文件操作,如果使用flock 鎖定文件拐云,必須保證在所有使用文件地方執(zhí)行 flock 才有意義。如果過(guò)早的系統(tǒng)因?yàn)椴恢С宙i定操作膳帕,函數(shù)執(zhí)行將沒(méi)有效果如FAT系統(tǒng)。
鎖定方式 | 說(shuō)明 |
---|---|
LOCK_SH | 取得共享鎖定(讀取的程序) |
LOCK_EX | 取得獨(dú)占鎖定(寫入的程序) |
LOCK_UN | 釋放鎖定(無(wú)論共享或獨(dú)占) |
LOCK_NB | 無(wú)法建立鎖定時(shí)危彩,此操作可不被阻斷,馬上返回進(jìn)程汤徽。通常與LOCK_SH或LOCK_EX 做OR組合使用。(Windows 系統(tǒng)上還不支持) |
讀鎖
1.php 文件內(nèi)容:
<?php
$handle = fopen('pf.txt','rb');
$stat = flock($handle,LOCK_SH);
sleep(5);
echo fgetss($handle);
flock($handle,LOCK_UN);
2.php
<?php
$handle = fopen('pf.txt','rb');
$stat = flock($handle,LOCK_SH);
echo fgetss($handle);
flock($handle,LOCK_UN);
讀鎖不能寫入文件可以讀取文件灸撰,并不會(huì)阻塞谒府。
寫鎖
1.php 文件內(nèi)容:
<?php
$handle = fopen('pf.txt','rb');
$stat = flock($handle,LOCK_EX);
sleep(5);
echo fgetss($handle);
flock($handle,LOCK_UN);
2.php
<?php
$handle = fopen('pf.txt','rb');
$stat = flock($handle,LOCK_SH);
echo fgetss($handle);
flock($handle,LOCK_UN);
寫鎖為獨(dú)占拼坎,所以讀取文件也會(huì)阻塞,前一個(gè)文件執(zhí)行完后才可以執(zhí)行第二個(gè)完疫。
防止阻塞
1.php
<?php
$handle = fopen('pf.txt','ab');
$stat = flock($handle,LOCK_EX);
sleep(5);
echo fgetss($handle);
flock($handle,LOCK_UN);
2.php
<?php
$handle = fopen('pf.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);
- 使用LOCK_NB當(dāng)文件被其他請(qǐng)求鎖定時(shí)泰鸡,腳本繼續(xù)向下執(zhí)行,鎖定失敗趋惨。
- 阻塞時(shí) $wouldblock 亦是為真
is_writable
判斷給定的文件名是否可寫
<?php
$filename = 'test.txt';
if (is_writable($filename)) {
echo 'The file is writable';
} else {
echo 'The file is not writable';
}
is_readable
判斷給定文件名是否可讀
<?php
$filename = 'test.txt';
if (is_readable($filename)) {
echo 'The file is readable';
} else {
echo 'The file is not readable';
}
file_exists
檢查文件或目錄是否存在
<?php
$filename = '/path/to/foo.txt';
if (file_exists($filename)) {
echo "The file $filename exists";
} else {
echo "The file $filename does not exist";
}
is_file
判斷給定文件名是否為一個(gè)正常的文件鸟顺。
is_dir
判斷給定文件名是否是一個(gè)目錄。
filesize
取得指定文件的大小器虾,返回文件大小的字節(jié)數(shù)讯嫂。
echo filesize('pf.txt');
file_put_contents
將一個(gè)字符串寫入文件。
參數(shù) | 說(shuō)明 |
---|---|
參數(shù)一 | 文件名 |
參數(shù)二 | 寫入的字符串 |
參數(shù)三 | FILE_APPEND:如果文件 filename 已經(jīng)存在兆沙,追加數(shù)據(jù)而不是覆蓋欧芽。LOCK_EX:在寫入時(shí)獲得一個(gè)獨(dú)占鎖。 |
file_get_content
將整個(gè)文件讀入一個(gè)字符串葛圃,如果打開遠(yuǎn)程文件需要開啟php.ini中的 allow_url_fopen 選項(xiàng)千扔。
filemtime
本函數(shù)返回文件中的數(shù)據(jù)塊上次被寫入的時(shí)間,也就是說(shuō)库正,文件的內(nèi)容上次被修改的時(shí)間曲楚。
下面是緩存文件的操作代碼,實(shí)際開發(fā)中的緩存控制還要注意很多細(xì)節(jié)褥符,下面是核心思路代碼龙誊。
<?php
//緩存文件存在并且沒(méi)有過(guò)期時(shí)使用緩存文件
if (is_file('1.cache.php') && filemtime('1.cache.php') > (time() - 10)) {
include '1.cache.php';
} else {
//開啟緩存區(qū)并保存解析數(shù)據(jù)到緩存文件
ob_start();
include '1.blade.php';
$content = ob_get_clean();
echo $content;
file_put_contents('1.cache.php', $content);
}
var_export
輸出或返回一個(gè)變量的字符串表示。
下面是將數(shù)組保存到文件中的代碼喷楣,并支持include 獲取數(shù)組數(shù)據(jù)趟大。
<?php
$user = [
['name'=>'PF大叔'],
['name'=>'小明']
];
$content =var_export($user,true);
file_put_contents('users.php','<?php return '.$content.';');
basename
返回路徑中的文件名部分
echo basename(__FILE__);
dirname
返回路徑中的目錄部分
echo dirname(__FILE__);
mkdir
支持遞歸的目錄創(chuàng)建,參數(shù)分別是:目錄铣焊、權(quán)限位逊朽、遞歸創(chuàng)建
mkdir('a/b/c',0755,true);
rmdir
刪除指定的目錄,該目錄必須是空的曲伊,而且要有相應(yīng)的權(quán)限叽讳。
rmdir('views');
rename
重命名一個(gè)文件或目錄,也可以進(jìn)行文件移動(dòng)坟募。
// 將1.html更名為a.html
rename('1.html','a.html');
//移動(dòng)文件1.html到目錄PFinal中
rename('1.html','PFinal/1.html');
copy
復(fù)制文件
//復(fù)制1.blade.php到目錄f中
copy('1.blade.php','f/1.blade.php');
常用常量
__DIR__
獲取文件所有目錄。
__FILE__
獲取文件的完整路徑,包含文件名昂利。
DIRECTORY_SEPARATOR
目錄分隔符,在 Windows 中蜂奸,斜線(/)和反斜線(\)都可以用作目錄分隔符扩所,但是在linux上使用(/),此常量會(huì)自動(dòng)根據(jù)系統(tǒng)設(shè)置為合適的分隔符助赞。
文件遍歷
opendir
opendir 函數(shù)類似于 fopen 操作方式雹食,可能獲取目錄指針讀取目錄群叶,下面是操作示例街立。
$handle = opendir('../php');
while (false!==($file = readdir($handle))) {
if (!in_array($file, ['.','..'])) {
echo filetype($file)."\t".$file.'<br/>';
}
}
closedir($handle);
scandir
列出指定路徑中的文件和目錄赎离。
foreach (scandir('../php') as $file) {
if (!in_array($file, ['.','..'])) {
echo filetype($file)."\t\t".$file.'<hr/>';
}
}
glob使用
尋找與模式匹配的文件路徑植阴。
參數(shù)順序?yàn)椋簠?shù)一文件路徑掠手,參數(shù)二選項(xiàng)標(biāo)記
下面是常用選項(xiàng)標(biāo)記
選項(xiàng) | 說(shuō)明 |
---|---|
GLOB_MARK | 在每個(gè)返回的項(xiàng)目中加一個(gè)斜線 |
GLOB_NOSORT | 按照文件在目錄中出現(xiàn)的原始順序返回(不排序) |
GLOB_NOCHECK | 如果沒(méi)有文件匹配則返回用于搜索的模式 |
GLOB_ERR | 停止并讀取錯(cuò)誤信息(比如說(shuō)不可讀的目錄)众雷,默認(rèn)的情況下忽略所有錯(cuò)誤 |
GLOB_BRACE | 設(shè)置多個(gè)匹配模式做祝,如:{.php,.txt} |
遍歷目錄
$files = glob('../../*');
print_r($files);
指定檢索文件類型
$files = glob('*.php', GLOB_ERR);
設(shè)置多個(gè)匹配模式
$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');
復(fù)制目錄
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');
移動(dòng)目錄
移動(dòng)目錄分兩步執(zhí)行编兄,第一步是復(fù)制目錄狠鸳,第二步是刪除目錄,所以使用上面兩個(gè)函數(shù)的綜合即可以卸察。
function moveDir($dir, $to):bool
{
copyDir($dir, $to);
return delDir($dir);
}