1. 程式人生 > 其它 >PHP中的檔案系統函式(二)

PHP中的檔案系統函式(二)

這次我們來學習的是一些不是太常用,但卻也非常有用的一些函式。它們中有些大家可能見過或者使用過,有一些可能就真的沒什麼印象了。它們都是 PHP 中檔案系統相關操作函式的一部分。存在即合理,或許只是我們的業務開發中還沒有接觸到而已。不管別的,先混個臉熟,在真正需要它們的時候你能馬上想起來 PHP 就自帶一個這樣的函式就可以了。

目錄判斷、建立、刪除、路徑快取資訊

var_dump(is_dir("./")); // bool(true)
var_dump(disk_free_space("./")); // float(7727517696)
var_dump(disk_total_space("./")); // float(250790436864)

is_dir() 函式估計大家會比較常用,就是用來判斷給定的路徑是否存在或者是否正常。一般在手動建立目錄之前都會使用這個函式來判斷一下目錄是否已經建立過了,常見於上傳相關的業務場景開發中。disk_free_space() 和 disk_total_space() 則是獲取指定目錄的剩餘磁碟空間和總的磁碟空間資料的函式。因為我的電腦是 Mac 系統,所以總的磁碟空間就是 250G 的,可用的空間為 7G ,看來馬上就要準備清理一下電腦了。

var_dump(mkdir("./a")); // bool(true)
var_dump(rmdir("./a"));  // bool(true)

mkdir() 函式用於建立一個目錄,它除了給定的路徑引數外,還有一個可選引數可以設定目錄的檔案許可權,也是傳遞 0777 之類的值就可以了,這個函式相信大家不會很陌生,大部分的檔案上傳分目錄的能力正是使用 is_dir() 來配合 mkdir() 進行目錄建立的。rmdir() 是用於刪除目錄的,這個函式有兩個前提,一是要刪除的目錄必須是空的,二是要有刪除這個目錄的許可權,如果任一條件不滿足的話,就會報出一個 E_WARNING 級別的錯誤。

realpath('./');
var_dump(realpath_cache_get());
// array(8) {
//     ["/Users/zhangyue/MyDoc/部落格文章/dev-blog/php/202010/source"]=>
//     array(4) {
//       ["key"]=>
//       float(1.4990943845035E+19)
//       ["is_dir"]=>
//       bool(true)
//       ["realpath"]=>
//       string(61) "/Users/zhangyue/MyDoc/部落格文章/dev-blog/php/202010/source"
//       ["expires"]=>
//       int(1603327834)
//     }
//     ["/Users/zhangyue/MyDoc/部落格文章"]=>
//     array(4) {
//       ["key"]=>
//       int(8597410586338680)
//       ["is_dir"]=>
//       bool(true)
//       ["realpath"]=>
//       string(34) "/Users/zhangyue/MyDoc/部落格文章"
//       ["expires"]=>
//       int(1603327834)
//     }
//     ["/Users"]=>
// ……
// ……

var_dump(realpath_cache_size()); // int(673)

realpath_cache_get() 函式用於獲取真實目錄快取的詳情,我們需要先使用 realpath() 獲得一個目錄路徑,然後就可以看到 realpath_cache_get() 裡面的內容。可以看出它返回的陣列中,是這條路徑從第一個目錄到這個目錄中的所有目錄資訊,包括每一級目錄的 realpath 、 is_dir 等屬性資訊。realpath_cache_size() 獲取的是真實路徑緩衝區的大小,也就是真實路徑快取區大小在記憶體中的使用量。

軟連線資訊

上篇文章中我們已經學過了如何建立連線檔案,這次我們再來看看兩個小的關於連線資訊的函式。

var_dump(readlink('ltest2.txt')); // "test.txt"
var_dump(is_link('ltest2.txt')); // bool(true)

readlink() 函式用於獲得軟連線所連線到的真實檔案的名稱。在上篇文章中,我們建立的 ltest2.txt 檔案正是 test.txt 檔案的軟連線。而 is_link() 函式則用於判斷給定的檔案是否是一個連線檔案。

拷貝、移動、改名、刪除檔案操作

var_dump(copy('test.txt', 'cp_test.txt')); // bool(true)

var_dump(is_file("cp_test.txt")); // bool(true)

var_dump(move_uploaded_file('test.txt', 'mv_upload_test.txt')); // bool(false)
var_dump(is_file("mv_upload_test.txt")); // bool(false)
var_dump(is_uploaded_file("mv_upload_test.txt")); // bool(false)

var_dump(copy('test.txt', 're_test.txt')); // bool(true)
var_dump(rename('re_test.txt', 'new_re_test.txt')); // bool(true)

var_dump(copy('test.txt', 'del_test.txt')); // bool(true)
var_dump(unlink("del_test.txt")); // bool(true)

對於檔案來說,copy() 是非常常用的一個函式。不管是寫程式碼還是日常辦公,複製貼上這樣的拷貝操作都是我們工作中的重心所在。PHP 提供的 copy() 函式就是專門用於檔案拷貝的,不過需要注意的是,一定要有檔案和拷貝目標目錄的讀寫許可權哦。

move_uploaded_file() 檔案相信大家也是非常熟悉的,在上傳檔案的操作中也是經常會用到的一個功能。不過需要注意的是,從檔名就可以看出,move_uploaded_file() 的作用是移動已上傳檔案,也就是 $_FILES 裡面 tmp 中的檔案,它是不能當做 copy() 函式來使用的。從演示程式碼中就可以看出,對於普通檔案來說,它是無法拷貝移動的。is_uploaded_file() 函式就是用於判斷要操作的檔案是不是一個 PHP 已上傳檔案。

通過上面這兩個函式,相信不少人都會想到檔案上傳中他們的使用,這裡就給出一個簡單的虛擬碼。

if(!move_uploaded_file('xxxx', 'xxxx')){
    if(copy('xxxx', 'xxxx')){
        // 上傳成功
    }else{
        // 上傳失敗
    }
}

很多教程裡都會有這樣的寫法,甚至一些框架中也會有這樣的寫法。其實就是先使用 move_uploaded_file() 去移動上傳檔案,如果失敗了,再使用 copy() 函式拷貝一次。如果還是失敗了,就認為整個上傳操作失敗了。

rename() 函式用於給檔案改名,其實它就是類似於 Linux 系統中的 mv 命令。

is_file() 函式用於判斷給定的檔案是否是一個正常的檔案。在作業系統中,特別是 Linux 系統中,一切皆檔案,所以這個函式真正最常用的場景是判斷給定的路徑到底是目錄還是一個檔案,很多時候我們會用它來判斷上傳成功後的檔案是否正常,或者判斷一個給定的路徑到底是一個目錄還是一個檔案。

最後就是 unlink() 函式。在 PHP 中,沒有 delete 或者 rm 這樣的函式,unlink() 就是用於刪除檔案的。不過它的名字起得卻像是要解除符號連線檔案的連線一樣,不管是連線檔案還是普通檔案,都是通過這個 unlink() 函式來進行刪除的。

檔案一次性讀取

關於檔案一次性讀取到內容和流式按位元組或行來讀取的內容我們之前已經有一篇文章詳細的學習講解過,大家可以移步 PHP大檔案讀取操作 中檢視。所以這裡我們就簡單的貼出程式碼演示一下。

var_dump(file_exists('test.txt')); // bool(true)
var_dump(readfile('test.txt')); // asdfasdfint(8)
var_dump(file('test.txt'));
// array(1) {
//     [0]=>
//     string(8) "asdfasdf"
//   }

$c = file_get_contents('test.txt');
var_dump($c); // string(8) "asdfasdf"

var_dump(file_put_contents('fpc_test.txt', $c)); // int(8)

file_exists() 函式是專業的用於判斷檔案是否存在的函式,上面的 is_file() 會更多地用於上傳之後的操作。而 file_exists() 則是在日常的程式碼編寫中非常常用的函式。readfile() 直接讀取檔案內容到內容中,file_get_contents() 也是這樣的功能,只不過 file_get_contents() 返回的是以字串為格式的檔案內容。注意看我們 var_dump() 的結果,file_get_contents() 明顯的標了是 string(8) 這樣的型別,而 readfile() 是直接輸出內容,不走緩衝區的,也就是說它是類似於 phpinfo() 這樣的函式。需要使用 ob_start() 之類的函式才能將 readfile() 函式讀取的內容放到一個變數中,我們之前的文章也專門講過緩衝區的概念,PHP中的輸出緩衝控制 。它的返回值是檔案的位元組數,也就是後面的 int(8) 。

file() 函式是將檔案的內容儲存到一個數組中,它會預設以行進行分隔,也就是每一行分為陣列中的一個元素。

file_put_contents() 是將給定的內容寫入到一個檔案中,和 file_get_contents() 配合也可以實現一個拷貝的操作。

檔案屬性

var_dump(fileatime('test.txt')); // int(1603243708)
var_dump(filectime('test.txt')); // int(1603242166)
var_dump(filemtime('test.txt')); // int(1603242166)

var_dump(fileinode('test.txt')); // int(8707958352)
var_dump(filesize('test.txt')); // int(8)
var_dump(filetype('test.txt')); // string(4) "file"

var_dump(is_executable('test.txt')); // bool(true)
var_dump(is_writable('test.txt')); // bool(true)
var_dump(is_readable('test.txt')); // bool(true)

很明顯,fileatime() 、filectime() 、filemtime() 對應的就是檔案的上次訪問時間、inode修改時間以及修改時間,和 Linux 系統中的檔案相關的那三個時間概念一致。fileinode() 用於獲得檔案的 inode 資訊。filesize() 就是檔案的大小,filetype() 是檔案的型別資訊。

is_executable() 用於判斷檔案是否可以執行,is_writable() 、is_readable() 判斷檔案是否可以寫和讀。這三個函式對應的就是檔案的許可權相關的判斷。

建立不重名檔案及臨時檔案

var_dump(tempnam('./', 't_')); // string(70) "/Users/zhangyue/MyDoc/部落格文章/dev-blog/php/202010/source/t_Gx6S5d"


$temp = tmpfile();
fwrite($temp, "writing to tempfile");
fseek($temp, 0);
// sleep(30); // /tmp/phpU2LZ3V 檔案
echo fread($temp, 1024), PHP_EOL; // writing to tempfile
fclose($temp); // 檔案直接被刪除了

tempnam() 函式會根據指定的 prefix 引數來生成一個隨機不重名的空檔案。在測試程式碼中,我們給定的 prefix 的值是 t_ ,最後生成的檔案就是 t_Gx655d 這樣一個空的檔案。

tmpfile() 在之前的文章中也講解過,它是生成一個臨時檔案,一般會放在 /tmp 目錄下(如果你沒有修改 php.ini 檔案中的相關設定的話)。這個函式建立檔案後會返回一個控制代碼,一旦使用 fclose() 關閉了這個檔案控制代碼,那麼檔案就馬上會被刪除掉。

按規則返回目錄內容

foreach (glob("*.txt") as $filename) {
    echo "$filename size: " . filesize($filename) , PHP_EOL;
}
// cp_test.txt size 8
// fpc_test.txt size 8
// ltest.txt size 8
// ltest2.txt size 8
// new_re_test.txt size 8
// test.txt size 8
// test3.txt size 0

foreach (glob("../../202009/*.md") as $filename) {
    echo "$filename size: " . filesize($filename) , PHP_EOL;
}
// ./../202009/1.PHP中的PDO操作學習(三)預處理類及繫結資料.md size: 16881
// ../../202009/10.PHP中非常好玩的Calendar擴充套件學習.md size: 8784
// ../../202009/11.學習PHP中的國際化功能來檢視貨幣及日期資訊.md size: 5521
// ../../202009/12.PHP中的日期相關函式(一).md size: 14217
// ../../202009/13.PHP中的日期相關函式(二).md size: 9858
// ../../202009/2.PHP中的PDO操作學習(四)查詢結構集.md size: 12825
// ../../202009/3.在PHP中使用SPL庫中的物件方法進行XML與陣列的轉換.md size: 6068
// ../../202009/4.PHP中的MySQLi擴充套件學習(一)MySQLi介紹.md size: 6029
// ../../202009/5.PHP中的MySQLi擴充套件學習(二)mysqli類的一些少見的屬性方法.md size: 9726
// ../../202009/6.PHP中的MySQLi擴充套件學習(三)mysqli的基本操作.md size: 9403
// ../../202009/7.PHP中的MySQLi擴充套件學習(四)mysqli的事務與預處理語句.md size: 3556
// ../../202009/8.PHP中的MySQLi擴充套件學習(五)MySQLI_STMT物件操作.md size: 7450
// ../../202009/9.PHP中的MySQLi擴充套件學習(六)MySQLI_result物件操作.md size: 10650

glob 函式也是之前有講解過的一個函式,它會根據指定的規則返回目錄中的所有檔案或者目錄資訊。可以方便地用於目錄地遍歷操作。注意這裡的規則引數不是完全的正則表示式,關於它具體支援的語法可以自行查閱相關的文件。

檔案 umask 操作

$old = umask(0);
echo $old, PHP_EOL; // 18
$now = umask();
echo $now, PHP_EOL; // 0

umask() 函式就是操作當前執行程序的 umask 資訊,和 Linux 中的 umask 命令一樣,用於指定當前建立的目錄檔案的預設許可權資訊。在 PHP 中,umask() 將 PHP 的 umask 設定為 mask & 0777 ,並返回原來的 umask 。當 PHP 被作為伺服器模組使用時,在每個請求結束後 umask 會被恢復。具體的 umask 知識大家可以參考 Linux 中的相關內容。

配置檔案資訊讀取

最後這兩個函式是用於讀取 PHP 型別的配置檔案資訊的,什麼叫 PHP 型別的配置檔案資訊?其實就是類似於 php.ini 檔案那樣的配置檔案,key=value 這種形式的配置檔案。就像 Laravel 的 .env 檔案也是可以使用這兩個函式進行讀取的。

var_dump(parse_ini_file('/usr/local/etc/php/7.3/php.ini'));
// array(133) {
//     ["#zend_extension"]=>
//     string(9) "xdebug.so"
//     ["extension"]=>
//     string(6) "vld.so"
//     ["engine"]=>
// ……
// ……

var_dump(parse_ini_file('/usr/local/etc/php/7.3/php.ini', true));
// array(38) {
//     ["#zend_extension"]=>
//     string(9) "xdebug.so"
//     ["extension"]=>
//     string(6) "vld.so"
//     ["PHP"]=>
//     array(45) {
//       ["engine"]=>
//       string(1) "1"
//       ["short_open_tag"]=>
// ……
// ……

parse_ini_file() 函式就是直接讀取指定路徑的配置檔案內容,在這裡我們直接測試的就是讀取 php.ini 檔案。它有一個可選引數,如果設定為 true 的話,返回的就是陣列分類的結構化的內容。

$ini = file_get_contents('/usr/local/etc/php/7.3/php.ini');
var_dump(parse_ini_string($ini));
// array(133) {
//     ["#zend_extension"]=>
//     string(9) "xdebug.so"
//     ["extension"]=>
//     string(6) "vld.so"
//     ["engine"]=>
// ……
// ……

var_dump(parse_ini_string($ini, true));
// array(38) {
//     ["#zend_extension"]=>
//     string(9) "xdebug.so"
//     ["extension"]=>
//     string(6) "vld.so"
//     ["PHP"]=>
//     array(45) {
//       ["engine"]=>
//       string(1) "1"
//       ["short_open_tag"]=>
// ……
// ……

parse_ini_string() 則是從給定的字串中讀取配置資訊,同樣也有一個格式化分組輸出的引數可選。它和 parse_ini_file() 是完全相同的,唯一的區別就是一個是從檔案路徑讀取,一個是從字串讀取。

總結

一口氣介紹了這麼多函式,大家是不是都用過呢?有人要說了,寫這玩意幹嘛,直接去看文件不就好了嘛?那可不一樣哦,文件中很多函式的介紹就一句話,示例程式碼也都是使用英文註釋的,咱這雖說也是一個搬運工,但咱不僅是簡單地搬運了一下,還把例子重寫了,另外還加上了一些應用場景的介紹哦!至於各位看官感覺好不好,那就仁者見仁,智者見智咯!

測試程式碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/7.PHP中的檔案系統函式(二).php

參考文件:

https://www.php.net/manual/zh/ref.filesystem.php

===============

關注公眾號:【硬核專案經理】獲取最新文章

新增微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、專案管理學習資料

知乎、公眾號、抖音、頭條搜尋【硬核專案經理】

B站ID:482780532