首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 文件與目錄操作核心 API 完整指南

     編輯:PHP 相關知識

文件操作基礎流程

PHP 文件操作遵循「打開 → 讀寫 → 關閉」三步驟,核心是資源句柄管理。本文系統梳理 8 大類常用操作與最佳實踐。

1. 打開文件:fopen()

<?php
// 模式說明
$modes = [
    'r'  => '只讀,指針開頭',
    'r+' => '讀寫,指針開頭',
    'w'  => '只寫,截斷/創建,指針開頭',
    'w+' => '讀寫,截斷/創建,指針開頭',
    'a'  => '只寫,指針結尾(追加),創建',
    'a+' => '讀寫,指針結尾(追加),創建',
    'x'  => '只寫,僅創建(存在失敗)',
    'x+' => '讀寫,僅創建(存在失敗)',
    'b'  => '二進制模式(推薦始終加上)',
    't'  => '文本模式(Windows換行轉換)'
];

// 實際使用
$fp = fopen('log.txt', 'rb');           // 相對路徑
$fp = fopen('../data/config.ini', 'rb'); // 相對路徑(上級)
$fp = fopen('https://example.com/api', 'rb'); // URL(需 allow_url_fopen=On)
$fp = fopen('ftp://user:pass@ftp.example.com/file', 'rb'); // FTP

// 安全打開模式
$filename = 'user_data.json';
$fp = @fopen($filename, 'rb');
if ($fp === false) {
    throw new RuntimeException("無法打開文件: $filename");
}
?>

2. 關閉文件:fclose()

<?php
// 必須顯式關閉,確保緩衝區刷新、釋放鎖、避免資源洩漏
fclose($fp);

// 最佳實踐:使用 try-finally 或註冊關閉函數
try {
    $fp = fopen('data.txt', 'wb');
    // ... 操作
} finally {
    if (isset($fp)) fclose($fp);
}

// 或使用自動資源管理 (PHP 8.0+)
$fp = fopen('data.txt', 'wb');
register_shutdown_function('fclose', $fp);
?>

3. 讀取文件:多種方式對比

函數用途特點適用場景
fgets()逐行讀取內存效率高、保留換行符大文本文件、日志分析
fgetss()逐行讀取+去標籤已棄用 PHP 8.0不推薦使用
fgetc()逐字符讀取極慢、精確控制特殊解析需求
fread()二進制塊讀取高性能、需指定長度圖片、大文件、網絡流
file_get_contents()一次性讀全文簡潔、大文件內存風險小配置文件、API 響應
file()讀入數組(每行一元素)自動去換行(可選)、內存佔用大行處理邏輯
SplFileObject面向對象迭代器功能豐富、可 Seek、CSV 解析現代 PHP 項目首選

大文件高效讀取模式

<?php
// 1. 塊讀取 (推薦 8KB-1MB)
$handle = fopen('large.log', 'rb');
while (!feof($handle)) {
    $chunk = fread($handle, 8192); // 8KB
    processChunk($chunk);
}
fclose($handle);

// 2. 行迭代 (內存友好)
$handle = fopen('large.csv', 'rb');
while (($line = fgets($handle)) !== false) {
    processLine(rtrim($line));
}
fclose($handle);

// 3. SplFileObject (現代最佳)
$file = new SplFileObject('large.csv', 'r');
$file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD);
foreach ($file as $fields) {
    processCsvRow($fields);
}
?>

4. 文件指針狀態判斷

<?php
$fp = fopen('data.bin', 'rb');

// 當前位置
$pos = ftell($fp); // 字節偏移

// 文件大小
$size = fstat($fp)['size']; // 或 filesize('data.bin')

// 是否到達末尾
if (feof($fp)) { /* EOF */ }

// 移動指針
fseek($fp, 0, SEEK_SET);   // 開頭
fseek($fp, -100, SEEK_END); // 倒數 100 字節
fseek($fp, 50, SEEK_CUR);   // 當前位置 +50

// 重置指針
rewind($fp); // 等同 fseek($fp, 0, SEEK_SET)
?>

5. 寫入文件

<?php
$filename = 'output.txt';
$content = "數據內容\n";

// 文本追加寫入
if (is_writable($filename)) {
    $fp = fopen($filename, 'ab'); // 追加二進制
    if ($fp) {
        $written = fwrite($fp, $content);
        if ($written === false) {
            throw new RuntimeException("寫入失敗");
        }
        fclose($fp);
    }
}

// 二進制寫入 (必須指定長度)
$binaryData = random_bytes(1024);
$fp = fopen('binary.dat', 'wb');
fwrite($fp, $binaryData, strlen($binaryData)); // 或 mb_strlen($data, '8bit')
fclose($fp);

// 原子寫入 (防止部分寫入被讀取)
$tmpFile = tempnam(sys_get_temp_dir(), 'atomic_');
file_put_contents($tmpFile, $content);
rename($tmpFile, $filename); // 同文件系統下原子操作
?>

6. 文件屬性與權限檢查

函數返回值說明
file_exists()bool文件/目錄是否存在
is_file()bool是否普通文件
is_dir()bool是否目錄
is_readable()bool當前進程可讀
is_writable()bool當前進程可寫
is_executable()bool可執行
filesize()int|false文件大小(字節)
filemtime()int|false最後修改時間戳
filectime()int|falseinode 變更時間
fileatime()int|false最後訪問時間
fileperms()int|false權限位掩碼
fileowner()int|false擁有者 UID
filegroup()int|false所屬組 GID
filetype()string|falsefile/dir/link/char/block/fifo/socket

權限掩碼解析

<?php
$perms = fileperms('script.php');
if ($perms !== false) {
    // 類型
    $type = ($perms & 0xF000) >> 12;
    // 擁有者權限
    $owner = ($perms & 0x01C0) >> 6;
    // 組權限
    $group = ($perms & 0x0038) >> 3;
    // 其他權限
    $other = $perms & 0x0007;
    
    printf("類型: %o, 權限: %o%o%o\n", $type, $owner, $group, $other);
    // 輸出如: 類型: 10, 權限: 644 (普通文件 rw-r--r--)
}
?>

7. 刪除與重命名

<?php
// 刪除文件
unlink('temp.txt'); // 失敗返回 false,不拋異常

// 刪除目錄 (必須為空)
rmdir('empty_dir');

// 遞刪除目錄樹
function rrmdir($dir) {
    $files = array_diff(scandir($dir), ['.', '..']);
    foreach ($files as $file) {
        $path = "$dir/$file";
        is_dir($path) ? rrmdir($path) : unlink($path);
    }
    rmdir($dir);
}

// 重命名/移動 (跨文件系統可能失敗)
rename('old_name.txt', 'new_name.txt');
rename('dir/file.txt', 'other_dir/file.txt'); // 移動
?>

8. 目錄操作

路徑處理函數

<?php
$path = '/var/www/html/index.php';

echo basename($path);        // index.php
echo basename($path, '.php'); // index
echo dirname($path);         // /var/www/html
echo realpath('../config');  // /var/www/config (解析絕對路徑)

$info = pathinfo($path);
/*
[
    'dirname' => '/var/www/html',
    'basename' => 'index.php',
    'extension' => 'php',
    'filename' => 'index'
]
*/
?>

目錄遍歷對比

方法風格特點推薦度
opendir/readdir過程式底層、需手動管理句柄⭐⭐
scandir()函數式返回數組、含 . 和 ..、大目錄內存壓力⭐⭐⭐
glob()模式匹配支持通配符、直接過濾⭐⭐⭐⭐
DirectoryIteratorOO 迭代器內存友好、豐富屬性方法⭐⭐⭐⭐⭐
RecursiveDirectoryIterator遞歸 OO遞歸遍歷、配合 FilterIterator⭐⭐⭐⭐⭐
FilesystemIterator增強迭代器跳過 . ..、路徑對象、可鏈式⭐⭐⭐⭐⭐

現代遍歷最佳實踐

<?php
// 1. 非遞歸:FilesystemIterator
$dir = new FilesystemIterator(__DIR__, FilesystemIterator::SKIP_DOTS);
foreach ($dir as $fileinfo) {
    echo $fileinfo->getFilename() . ' (' . $fileinfo->getSize() . " bytes)\n";
}

// 2. 遞歸 + 過濾:僅獲取 .php 文件
$phpFiles = new RegexIterator(
    new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS)
    ),
    '/\.php$/i'
);

foreach ($phpFiles as $file) {
    echo $file->getPathname() . "\n";
}

// 3. 目錄操作
mkdir('new_dir', 0755, true); // 遞歸創建
chdir('new_dir');             // 改變工作目錄
echo getcwd();                // 獲取當前工作目錄
?>

錯誤處理與性能優化

統一異常處理

<?php
function safeFileOperation(callable $operation, string $context = '') {
    try {
        return $operation();
    } catch (Throwable $e) {
        error_log("文件操作失敗 [$context]: " . $e->getMessage());
        throw new RuntimeException("文件操作失敗: $context", 0, $e);
    }
}

// 使用
$content = safeFileOperation(function() {
    return file_get_contents('config.json');
}, '讀取配置文件');
?>

性能優化清單

  1. 大文件流式處理:避免 file_get_contents 讀入內存
  2. 減少 stat 系統調用:緩存 file_exists/filesize 結果
  3. 使用 opcache:PHP 文件本身受益於字節碼緩存
  4. 批量操作:合併多次寫入、使用 flock 適當鎖定
  5. SSD/NFS 調優:根據存儲介質調整塊大小、並發數

總結

PHP 文件系統 API 豐富但易混淆,現代開發建議:

  • 優先使用 SplFileObject / FilesystemIterator 面向對象接口
  • 大文件採用 流式讀寫,小文件用 file_get_contents/file_put_contents
  • 路徑操作統一用 pathinfo/realpath,避免手動拼接
  • 關鍵操作添加 原子寫入、異常處理、權限檢查
  • 目錄遍歷根據深度選擇 glob 或 RecursiveDirectoryIterator
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved