核心流程:打開 → 讀/寫 → 關閉
<?php
// 1. 打開文件(資源句柄)
$fp = fopen('tmp.html', 'r'); // 'r' 唯讀,指針在開頭
if (!$fp) {
die("無法打開文件");
}
// 2. 讀取內容(兩種方式)
// 方式 A:fread + filesize(傳統)
$content = fread($fp, filesize('tmp.html'));
// 方式 B:file_get_contents(現代、簡潔、推薦)
$content = file_get_contents('tmp.html');
// 3. 寫入文件
$fw = fopen('news.html', 'w'); // 'w' 寫入,截斷文件/創建新文件
fwrite($fw, $content);
// 4. 關閉資源(必須!防止句柄洩漏)
fclose($fp);
fclose($fw);
echo $content;
文件模式速查表
| 模式 | 說明 | 指針位置 | 文件不存在 | 截斷文件 |
r | 唯讀 | 開頭 | 失敗 | 否 |
r+ | 讀寫 | 開頭 | 失敗 | 否 |
w | 唯寫 | 開頭 | 創建 | 是 |
w+ | 讀寫 | 開頭 | 創建 | 是 |
a | 追加 | 結尾 | 創建 | 否 |
a+ | 讀取+追加 | 結尾 | 創建 | 否 |
x | 唯寫創建 | 開頭 | 創建/失敗(存在) | 否 |
c | 唯寫不截斷 | 開頭 | 創建 | 否 |
現代簡化函數(推薦優先使用)
| 操作 | 傳統流程 | 現代函數 | 優點 |
| 讀取全文 |
fopen → fread → fclose |
file_get_contents($path) |
單行、自動關閉、支援 URL |
| 寫入全文 |
fopen → fwrite → fclose |
file_put_contents($path, $data) |
單行、原子寫入(LOCK_EX)、追加模式 |
| 讀取為數組 |
fopen → fgets 循環 → fclose |
file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) |
自動分行、過濾空行 |
| 逐行處理大文件 |
fopen → fgets 循環 |
SplFileObject 迭代器 |
內存友好、面向對象、可跳轉 |
file_put_contents 進階用法
<?php
// 追加模式(不覆蓋)
file_put_contents('log.txt', "新日誌\n", FILE_APPEND);
// 獨佔鎖(防止併發寫入衝突)
file_put_contents('counter.txt', $newValue, LOCK_EX);
// 組合:追加 + 鎖
file_put_contents('log.txt', $entry, FILE_APPEND | LOCK_EX);
大文件處理:SplFileObject 迭代器
<?php
// 處理 1GB 日誌文件,內存常數級
$file = new SplFileObject('huge.log', 'r');
$file->setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
foreach ($file as $lineNum => $line) {
if (strpos($line, 'ERROR') !== false) {
echo "Line {$lineNum}: {$line}\n";
}
// 達到條件可 break,無需讀完整個文件
}
// 寫入大文件
$out = new SplFileObject('output.csv', 'w');
$out->fputcsv(['ID', 'Name', 'Email']);
foreach ($users as $user) {
$out->fputcsv([$user->id, $user->name, $user->email]);
}
編碼處理:讀取 GBK 文件輸出 UTF-8
<?php
$gbkContent = file_get_contents('legacy_gbk.txt');
$utf8Content = iconv('GBK', 'UTF-8//IGNORE', $gbkContent);
file_put_contents('converted_utf8.txt', $utf8Content);
安全與錯誤處理
- 路徑遍歷防護:
realpath($input) 解析真實路徑,驗證在允許目錄內
- 文件上傳處理: 必須用
move_uploaded_file(),驗證 MIME、大小、擴展名
- 錯誤抑制: 避免
@fopen(),改用 if ($fp = @fopen(...)) 或 try-catch (配合 set_error_handler)
- 並發安全: 寫入用
LOCK_EX,讀取用 LOCK_SH(flock() 或 file_put_contents 旗標)