處理大型日誌或數據文件時,若需修改特定行內容,逐行讀入內存再寫回不現實。PHP 提供文件指針操作函數(fseek、fgets、fwrite)及 SPL 的 SplFileObject,可實現隨機存取與就地修改。
<?php
$fp = fopen('d:/file.txt', 'r+'); // 讀寫模式打開
if ($fp) {
$i = 1;
while (!feof($fp)) {
// 目標:修改第 2 行
if ($i == 2) {
// 關鍵:fgets 讀取後指針指向行尾(即下一行開頭)
// 若要修改第 2 行自身,需在 fgets 前定位
fseek($fp, 2, SEEK_CUR); // 相對當前位置偏移 2 字節
fwrite($fp, '#'); // 覆蓋寫入(非插入)
break;
}
fgets($fp); // 讀取一行,指針移至下一行開頭
$i++;
}
fclose($fp);
}
?>
r+:以讀寫方式打開,指針初始位於文件開頭,文件必須存在。fgets() 指針行為:讀取一行後,指針停留在該行結尾的換行符後(即下一行開頭)。fwrite() 覆蓋特性:寫入時從當前指針位置開始覆蓋原有字節,而非插入。若寫入內容長度超過原有行剩餘長度,會繼續覆蓋後續內容。fseek() 定位:SEEK_CUR 相對當前位置偏移;SEEK_SET 相對文件開頭;SEEK_END 相對文件末尾。因 fwrite 為覆蓋模式,若需插入內容(如在行中間插入字符),需採用臨時文件法:
rename() 原子操作)。此法雖需額外 I/O,但能保證數據完整性,適用於大文件插入/刪除行場景。
PHP 5.1+ 引入 SPL,SplFileObject 提供更豐富的介面:
<?php
$fp = new SplFileObject('d:/file.txt', 'r+');
// seek(1) 移至第 2 行(索引從 0 起),指針指向行尾
$fp->seek(1);
$line = $fp->current(); // 獲取第 2 行內容
// 操作第 3 行(指針當前在行尾)
$fp->fseek(2, SEEK_CUR);
$fp->fwrite('#');
?>
foreach ($file as $line) 遍歷,自動處理換行。key() 返回行號,current() 返回行內容。fgetcsv() 直接解析 CSV 格式。seek()、fseek()、rewind() 多種定位方式。| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 簡單覆蓋修改固定位置行 | 原生 fseek/fwrite | 輕量、無額外開銷 |
| 需插入/刪除行、結構化處理 | 臨時文件法 + SplFileObject | 功能豐富、代碼可維護性高 |
| 超大文件(GB 級)隨機存取 | 考慮 mmap 擴展或外部工具 | PHP 用戶態複製開銷大 |
掌握文件指針操作與 SplFileObject,能高效解決大文件隨機讀寫需求。核心原則:理解指針移動語義,區分覆蓋與插入,選擇恰當策略。