導語####
任何類型的變量娇钱,都是在程序運行期間才將數(shù)據(jù)加載到內(nèi)存中的泞莉,并不能持久保存馍管。如果需要將數(shù)據(jù)長久保存起來掸掏,以便后期程序再次運行時還可以使用茁影,存儲的基本方法通常有兩種:將需要持久化的數(shù)據(jù)保存到普通文件或數(shù)據(jù)庫中。而對文件的處理因為比較繁瑣丧凤,所以并不是用來持久儲存數(shù)據(jù)的首選募闲,但在任何計算機設備中,文件都是必需的對象愿待,尤其是在Web編程中浩螺,文件的操作是非常有用的,我們可以在客戶端通過訪問PHP腳本程序仍侥,動態(tài)地在Web服務器上生成目錄要出,創(chuàng)建、編輯农渊、修改文件厨幻,像開發(fā)采集程序、網(wǎng)頁靜態(tài)化腿时、文件上傳及下載等操作都離不開文件處理况脆。
一、文件####
1批糟、文件類型
PHP是以UNIX的文件系統(tǒng)為模型的格了,因此在Windows系統(tǒng)中我們只能獲得"file"、"dir"徽鼎、"unknown"三種文件類型盛末。而在UNIX系統(tǒng)中弹惦,我們可以獲得"block"、"char"悄但、"dir"棠隐、"fifo"、"file"檐嚣、"link"或"unknown"7種文件類型助泽。
fileType: 獲取文件的類型,該函數(shù)接受一個文件名為參數(shù)嚎京,如果文件不存在返回false嗡贺。
2、文件屬性
函數(shù)名 | 作用 | 參數(shù) | 返回值 |
---|---|---|---|
file_exists() | 檢查文件是否存在 | 文件名 | 文件存在返回TRUE |
filesize() | 取得文件大小 | 文件名 | 返回文件大小的字節(jié)數(shù) |
is_readable() | 判斷文件名是否可讀 | 文件名 | 存在且可讀返回TRUE |
is_writable() | 判斷文件名是否可寫 | 文件名 | 存在且可讀寫返回TRUE |
is_executable() | 判斷文件名是否可執(zhí)行 | 文件名 | 存在且可執(zhí)行返回TRUE |
filectime() | 獲取文件的創(chuàng)建時間 | 文件名 | 返回UNIX時間戳格式 |
filemtime() | 獲取文件的修改時間 | 文件名 | 返回UNIX時間戳格式 |
fileatime() | 獲取文件的訪問時間 | 文件名 | 返回UNIX時間戳格式 |
stat() | 獲取文件的大部分屬性 | 文件名 | 返回文件有用信息的數(shù)組 |
代碼示例:
/*聲明一個函數(shù)鞍帝,通過傳入一個文件名獲取文件的部分屬性*/
function getFilePro($fileName){
//如果文件或目錄不存在诫睬,則直接退出目錄
if(!file_exists($fileName)){
echo "目標文件不存在<br/>";
return;
}
//判斷是否是一個普通文件
if(is_file($fileName)){
echo $fileName . "是一個文件<br/>";
}
//判斷是否是一個目錄
if(is_dir($fileName)){
echo $fileName . "是一個目錄<br/>";
}
//用定義的函數(shù)輸出文件類型
echo "文件類型:" . getFileType($fileName) . "<br/>";
//用定義的函數(shù)輸出文件大小
echo "文件大小:" . getFileSize(fileSize($fileName)) . "<br/>";
//判斷文件是否可讀
if(is_readable($fileName)) echo "文件可讀<br/>";
//判斷文件是否可寫
if(is_writable($fileName)) echo "文件可寫<br/>";
//判斷文件是否可以執(zhí)行
if(is_executable($fileName)) echo "文件可執(zhí)行<br/>";
echo "文件創(chuàng)建時間:" . date("Y年m月j日",filectime($fileName)) . "<br/>;
echo "文件最后修改時間:" . date("Y年m月j日",filemtime($fileName)) . "<br/>";
echo "文件最后打開時間:" . date("Y年m月j日",fileatime($fileName)) . "<br/>";
/**聲明一個函數(shù)帕涌,用來返回文件的類型**/
function getFileType($fileName){
switch(fileType($fileName)){
case 'file' : $type = "普通文件"; break;
case 'dir' : $type = "目錄文件"; break;
case 'block' : $type = "塊設備文件"; break;
case 'char' : $type = "字符設備文件"; break;
case 'fifo' : $type = "命名管道文件"; break;
case 'link' : $type = "符號鏈接"; break;
case 'unknown : $type = "未知文件"; break;
default : $type = "沒有檢測到文件類型"; break;
}
return $type;
}
}
/**聲明一個函數(shù)摄凡,用來返回文件的大小**/
function getFileSize($bytes){
if($bytes >= pow(2,40)){
$res = round($bytes / pow(1024,4),2);
$suffix = "TB";
}else if($bytes >= pow(2,30)){
$res = round($bytes / pow(1024,3),2);
$suffix = "GB";
}else if($bytes >= pow(2,20)){
$res = round($bytes / pow(1024,2),2);
$suffix = "MB";
}else if($bytes >= pow(2,10)){
$res = round($bytes / pow(1024,1),2);
$suffix = "KB";
}else{
$res = $bytes;
$suffix = "Bytes";
}
return $res . " " . $suffix;
}
二、目錄####
1蚓曼、解析目錄路徑
- 絕對路徑:從根目錄開始一級一級地進入各個子目錄架谎,最后指定改文件名或目錄名。
- 相對路徑:從當前目錄進入某目錄辟躏,最后指定改文件名或目錄名谷扣。
在系統(tǒng)的每個目錄下都有兩個特殊的目錄“.”和“..”,分別指示當前目錄和當前目錄的父目錄
在UNIX系統(tǒng)和Windows系統(tǒng)中捎琐,目錄分隔符是不同的会涎,在UNIX系統(tǒng)中必須使用正斜線“/”作為路徑分隔符,而在Windows系統(tǒng)中默認使用反斜線“\”作為路徑分隔符瑞凑,在程序中表示時還要將“\”轉義末秃,但也接受正斜線“/”的寫法。建議都是用“/”作為文件的路徑分隔符籽御。另外练慕,也可以使用PHP內(nèi)置常量DIRECTORY_SEPARATOR,其值為當前操作系統(tǒng)的默認文件路徑分隔符技掏。
下面為幾個常用的函數(shù):
basename():返回路徑中的文件名部分
dirname():返回去掉文件名后的目錄名
pathinfo():返回一個關聯(lián)數(shù)組铃将,包含路徑中的目錄名、基本名哑梳、擴展名
2劲阎、遍歷目錄
opendir():打開指定目錄,接受一個目錄的路徑及目錄名作為參數(shù)鸠真,函數(shù)返回值為可供其他目錄函數(shù)使用的目錄句柄(資源類型)悯仙。如果該目錄不存在或沒有訪問權限龄毡,則返回false。
readdir():用于讀取指定目錄锡垄,接受已經(jīng)用opendir()打開的卡操作目錄句柄作為參數(shù)沦零,函數(shù)返回當前目錄指針位置的一個文件名,并將目錄指針向后移動一位货岭。當指針位于目錄的結尾使路操,因為沒有文件存在則返回false。
closedir():關閉指定目錄茴她,接受已經(jīng)用opendir()打開的可操作目錄句柄作為參數(shù),函數(shù)無返回值程奠,運行后將關閉打開的目錄丈牢。
rewinddir():倒回目錄句柄,接受已經(jīng)用opendir()打開的可操作目錄句柄作為參數(shù)瞄沙,將目錄指針重置目錄到開始處己沛,即倒回目錄的開頭。
代碼示例:
/****完整的遍歷目錄下所有的指定文件類型函數(shù)****/
function traverse($path = '.') {
$current_dir = opendir($path); //opendir()返回一個目錄句柄,失敗返回false
while(($file = readdir($current_dir)) !== false) { //readdir()返回打開目錄句柄中的一個條目
//$sub_dir = $path . DIRECTORY_SEPARATOR . $file; //構建子目錄路徑 DIRECTORY_SEPARATOR 代表反斜線 \
$sub_dir = $path . '/' . $file;
if($file == '.' || $file == '..') {
continue;
} else if(is_dir($sub_dir)) { //如果是目錄,進行遞歸
echo 'Directory ' . $file . ':<br>';
traverse($sub_dir);
} else { //如果是文件,直接輸出
echo 'File in Directory ' . $path . ': ' . $file . '<br>';
}
}
}
traverse('../../');
3距境、統(tǒng)計目錄大小
代碼示例:
/**自定義一個函數(shù)申尼,用于統(tǒng)計傳入?yún)?shù)的目錄大小**/
function getDirSize($dirName){
$dir_size = 0; //用來累計各個文件大小
if($dir_handle = opendir($dirName)){
while(($file = readdir($dir_handle)) !== false){
if($file == '.' || $file == '..') continue; //排除兩個特殊目錄
$subFile = $dirName . DIRECTORY_SEPARATOR . $file; //將目錄下的子文件和當前目錄相連
if(is_dir($subFile)){
$dir_size += getDirSize($subFile); //遞歸地調(diào)用自身函數(shù),求子目錄的大小
}else{
$dir_size += filesize($subFile);
}
}
closedir($dir_handle);
}
return $dir_size;
}
4垫桂、建立和刪除目錄
mkdir():創(chuàng)建目錄【以最高權限創(chuàng)建目錄 mkdir(目錄名,0777,true)】
rmdir():刪除目錄师幕,只能刪除一個空目錄并且目錄必須存在
自定義遞歸函數(shù)刪除目錄的示例代碼:
function delDir($dir){
if(file_exists($dir)){ //如果不存在rmdir(0函數(shù)會出錯
if($dir_handle = @opendir($dir)){ //打開目錄并判斷是否成功
while(($file = readdir($dir_handle)) !== false){ //循環(huán)便利目錄
if($file == '.' || $file == '..') continue; //一定要排除兩個特殊的目錄
$subFile = $dir . DIRECTORY_SEPARATOR . $file; //將目錄下的文件和當前目錄相連
if(is_dir($subFile)){ //如果是目錄則條件成立
delDir($subFile); //遞歸
}else{
unlink($subFile); //刪除文件
}
}
closedir($dir_handle);
rmdir($dir); //刪除空目錄
}
}
}
5、復制目錄
function copyDir($dirSrc,$dirTo){
if(is_file($dirTo)){
echo "目標不是目錄不能創(chuàng)建";
return;
}
if(!file_exists($dirTo)){
mkdir($dirTo,0777,true);
}
if($dir_handle = @opendir($dirSrc)){
while(($file = readdir($dir_handle)) !== false){
if($file == '.' || $file == '..') continue;
$subSrcFile = $dirSrc .DIRECTORY_SEPARATOR . $file;
$subToFile = $dirTo . DIRECTORY_SEPARATOR . $file;
if(is_dir($subSrcFile)){
copyDir($subSrcFile,$subToFile);
}
if(is_file($subSrcFile)){
copy($subSrcFile,$subToFile);
}
}
closedir($dir_handle);
}
}
copyDir('vendor','photos/vendor');
三诬滩、文件的基本操作####
1霹粥、文件的打開與關閉
- fopen():打開文件,建立與文件資源的連接疼鸟,并使文件指針指向文件后控。
- fclose():關閉文件,即斷開文件指針與文件之間的聯(lián)系空镜。
在fopen()中第二個參數(shù)可以使用的文件模式
模式 | 描述 |
---|---|
r | 只讀方式打開文件浩淘,從文件開頭開始讀 |
r+ | 讀寫方式打開文件,從文件開頭開始讀寫 |
w | 只寫方式打開文件吴攒,從文件開頭開始寫张抄。如果文件已經(jīng)存在,將文件指針指向文件頭并將文件大小截為零洼怔,即刪除所有文件已有的內(nèi)容欣鳖。如果文件不存在,函數(shù)將創(chuàng)建這個文件 |
w+ | 讀寫方式打開文件茴厉,從文件頭開始讀寫泽台。如果文件已經(jīng)存在什荣,將文件指針指向文件頭并將文件大小截為零,即刪除所有文件已有的內(nèi)容怀酷。如果該文件不存在則嘗試創(chuàng)建它稻爬,僅能用于本地文件 |
x | 創(chuàng)建并以寫入方式打開,將文件指針指向文件頭蜕依。如果文件已經(jīng)存在桅锄,則fopen()調(diào)用失敗并返回false,并生成一條E_WARNING級別的錯誤信息。如果文件不存在則嘗試創(chuàng)建它样眠,僅能用于本地文件 |
x+ | 創(chuàng)建并以讀寫方式打開友瘤,將文件指針指向文件頭。如果文件已經(jīng)存在檐束,則fopen()調(diào)用失敗并返回false,并生成一條E_WARNING級別的錯誤信息辫秧。如果文件不存在則嘗試創(chuàng)建它,僅能用于本地文件 |
a | 寫入方式打開被丧,將文件指針指向文件末尾盟戏。如果該文件已有內(nèi)容,將從該文件末尾開始追加甥桂。如果該文件不存在柿究,函數(shù)將創(chuàng)建這個文件 |
a+ | 寫入方式打開,將文件指針指向文件末尾黄选。如果該文件已有內(nèi)容蝇摸,將從該文件末尾開始追加或讀。如果該文件不存在办陷,函數(shù)將創(chuàng)建這個文件 |
b | 以二進制模式打開文件探入,用于與其他模式進行連接。如果文件系統(tǒng)能夠區(qū)分二進制文件和文本文件懂诗,你可能會用到它蜂嗽。例如在Windows系統(tǒng)中可以分區(qū),而Unix系統(tǒng)則不分區(qū)殃恒。這個模式是默認的模式 |
t | 以文本模式打開文件植旧,這個模式也只是Windows系統(tǒng)下的一個選項,不推薦使用 |
2离唐、寫入文件
fwrite(): 將字符串寫入到文件中病附,參數(shù)1為fopen打開的文件資源,參數(shù)2為要寫入的內(nèi)容亥鬓,參數(shù)3是寫入到第length個 字符時停止寫入完沪。
代碼示例:
$file = "demo.txt";
$handler = fopen($file,"r") or die('Could not open ' .$file); //以只讀模式打開
//循環(huán)10次寫入
for($i=0;$i<10;$i++){
fwrite($handler,$i ."-Hello world\n");
}
fclose($handler); //關閉指針資源
3、讀取文件內(nèi)容
讀取文件的內(nèi)容函數(shù),如下表
函數(shù) | 描述 |
---|---|
fread() | 讀取打開的文件 |
file_get_contents() | 將文件讀入字符串 |
fgets() | 從打開的文件中返回一行 |
fgetc() | 從打開的文件中返回字符 |
file() | 把文件讀入一個數(shù)組中 |
readfile() | 讀取一個文件覆积,并輸出到輸出緩沖 |
fread()
feof():判斷一個文件指針是否位于文件的結束處
代碼示例:
$file = "test.txt";
$handle = fopen($file,"r") or die("文件打開失敗");
$contents = fread($handle,50); //從文件讀取前50個字節(jié)
echo $contents;
/**從文件中讀取全部內(nèi)容存入到一個變量中听皿,每次讀取一部分,循環(huán)讀取**/
$file = "./photos/7141730.png"; //二進制文件
$handle = fopen($file,"rb") or die("文件打開失敗");
$contents = "";
while(!feof($handle)){ //判斷文件是否結尾
$contents .= fread($handle,1024);
}
fclose($handle);
echo $contents;
/**另一種從文件中讀取全部內(nèi)容的方法**/
$file = "test.txt";
$handle = fopen($file,"r") or die("文件打開失敗");
$contents = fread($handle,filesize($file));
fclose($handle);
echo $contents;
file_get_contents() 如果只是將一個文件的內(nèi)容讀到一個字符串中宽档,file_get_contents()性能要高一些
fgets()和fgetc()
代碼示例:
$file = "./test.txt";
$handle = fopen($file,"r") or die("文件打開失敗");
while(!feof($handle)){
$contents = fgets($handle,4096);
echo $contents . "<br/>"; //輸出每一行
}
fclose($handle);
$handle = fopen($file,"r") or die("文件打開失敗");
while(false !== ($char = fgetc($handle))){
echo $char . "<br/>"; //輸出單個字符
}
fclose($handle);
file():與file_get_contents()類似尉姨,不需要使用fopen()打開文件。它可以把整個文件讀入到一個數(shù)組中吗冤。數(shù)組中的每個元素對應文件中的相應的行又厉,各元素由換行符分隔,同時換行符仍附加在每個元素的末尾椎瘟。
代碼示例:
echo "<pre>";
print_r(file("test.txt"));
echo "</pre>";
readfile():該函數(shù)可以讀取指定的文件覆致,立即輸出到輸出緩沖區(qū),并返回讀取的字節(jié)數(shù)肺蔚,不需要使用fopen()打開文件煌妈。
代碼示例:
readfile("test.txt");
4、訪問遠程文件
- 對遠程文件進行讀操作
代碼示例:
//通過http打開遠程文件 只讀模式
$file = fopen("http://www.baidu.com","r") or die("打開遠程文件失敗");
//循環(huán)從文件中讀取的內(nèi)容
while(!feof($file)){
$line = fgets($file,1024); //每讀取一行
//如果找到遠程文件的標題標記則取出標題婆排,并退出循環(huán)声旺,不在讀取文件
if(preg_match("/<title>(.*)<\/title>/",$line,$out)){
$title = $out[1];
break;
}
}
fclose($file);
echo $title;
- 對遠程文件進行寫操作
//在遠程服務器上創(chuàng)建文件笔链,以寫的模式打開
$file = fopen("ftp://user:password@ftp.域名.net/path/file","w");
//將一個字符串寫入到遠程服務器中
fwrite($file,"hello world");
//關閉文件資源
fclose($file);
5段只、文件的鎖定機制
多個客戶端用戶在同一時刻對服務器上的同一文件訪問的情況下,如果一個用戶正向文件中寫入數(shù)據(jù)鉴扫,當還沒有寫完時赞枕,其他用戶在這一時刻也向這個文件中寫入數(shù)據(jù),就會造成數(shù)據(jù)寫入混亂坪创。還有炕婶,當用戶沒有將數(shù)據(jù)寫完,其他用戶就去獲取這個文件的內(nèi)容莱预,也會得到殘缺的數(shù)據(jù)柠掂。
flock():可以對文件使用鎖定機制
代碼示例:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<?php
//聲明一個變量保存文件名,在這個文件中保存留言信息
$filename = "text_data.txt";
//判斷用戶是否按下提交按鈕依沮,用戶提交后則條件成功
if(isset($_POST['sub'])){
//接收表單內(nèi)容涯贞,并整合為一條,使用'||'分隔危喉,使用'<|>'結尾
$message = $_POST['username'] . "||" . $_POST['title'] . "||" . $_POST['mess'] . "<|>";
writeMessage($filename,$message); //調(diào)用自定義函數(shù)宋渔,將信息寫入文件
}
//判斷文件是否存在,如果存在辜限,讀取數(shù)據(jù)
if(file_exists($filename)){
readMessage($filename);
}
/**
* 自定義一個函數(shù)皇拣,用于向文件中寫入數(shù)據(jù)
* @param $filename 文件名
* @param $message 寫入的內(nèi)容
*/
function writeMessage($filename,$message){
$fp = fopen($filename,"a"); //以追加的模式打開文件
if(flock($fp,LOCK_EX)){ //進行排他型鎖定(獨占鎖定)
fwrite($fp,$message); //寫入文件
flock($fp,LOCK_UN); //釋放鎖定
}else{
echo "不能鎖定文件";
}
fclose($fp); //關閉文件資源
}
/**
* 自定義函數(shù),用來遍歷讀取文件
* @param $filename 文件名
*/
function readMessage($filename){
$fp = fopen($filename,"r"); //以只讀模式打開文件
flock($fp,LOCK_SH); //建立文件的共享鎖定
$buffer = "";
while(!feof($fp)){
$buffer .= fread($fp,1024); //讀出數(shù)據(jù)后追加到$buffer變量中
}
$data = explode("<|>",$buffer); //將數(shù)據(jù)轉換為數(shù)組薄嫡,以"<|>"分隔
//遍歷數(shù)組氧急,以html格式輸出
foreach($data as $line){
//將每行數(shù)據(jù)再分隔
@list($username,$title,$message) = explode("||",$line);
//判斷每部分是否為空
if($username != "" && $title != "" && $message != ""){
echo $username . '說:';
echo ' '. $title. ', ';
echo $message . "<hr>";
}
}
flock($fp,LOCK_UN); //釋放鎖定
fclose($fp);
}
?>
<form action="" method="post">
用戶名:<input type="text" name="username" size="10" id=""><br/>
標 題:<input type="text" name="title" size="30" id=""><br/>
<textarea name="mess" id="" cols="41" rows="4"></textarea>
<input type="submit" value="留言" name="sub">
</form>
</body>
</html>
6颗胡、文件的一些基本操作函數(shù)
函數(shù) | 語法結構 | 描述 |
---|---|---|
copy() | copy(來源文件,目的文件) | 復制文件 |
unlink() | unlink(目標文件) | 刪除文件 |
ftruncate() | ftruncate(目標文件資源,截取長度 | 將文件截取到指定長度 |
rename() | rename(舊文件名,新文件名) | 重命名文件或目錄 |