根據 PHP 版本、併發需求、資料大小選擇適當寫入策略,確保資料一致性與效能。
<?php
$file = 'dirlist.php';
$data = '要寫入的內容';
// 1. 檢查可寫性
if (!is_writable($file)) {
die("檔案 $file 不可寫");
}
// 2. 寫入(自動處理開啟/關閉、支援 FLAGS)
$bytes = file_put_contents($file, $data, LOCK_EX); // 獨佔鎖防止併發衝突
if ($bytes === false) {
die("寫入失敗");
}
echo "成功寫入 $bytes 位元組";
?>
LOCK_EX 獨佔鎖、支援 FILE_APPEND 追加模式。LOCK_EX(獨佔鎖)、FILE_APPEND(追加)、FILE_TEXT(文字模式,Windows 相關)。<?php
$file = 'dirlist.php';
$data = '要寫入的內容';
if (!is_writable($file)) die("不可寫");
$handle = fopen($file, 'wb'); // 'wb' 二進制寫入,截斷檔案
if (!$handle) die("無法開啟檔案");
// 可選:獨佔鎖
if (!flock($handle, LOCK_EX)) {
fclose($handle);
die("無法取得鎖");
}
$written = fwrite($handle, $data);
if ($written === false) {
flock($handle, LOCK_UN);
fclose($handle);
die("寫入失敗");
}
flock($handle, LOCK_UN);
fclose($handle);
echo "寫入 $written 位元組";
?>
<?php
function atomic_put_contents(string $filename, string $data, int $flags = 0): bool {
$temp = $filename . '.tmp.' . uniqid('', true);
$bytes = @file_put_contents($temp, $data, $flags | LOCK_EX);
if ($bytes === false) {
@unlink($temp);
return false;
}
// rename 在同一檔案系統上是原子操作
if (!@rename($temp, $filename)) {
@unlink($temp);
return false;
}
return true;
}
// 使用
if (atomic_put_contents('config.json', json_encode($config))) {
echo "原子寫入成功";
}
?>
rename() 覆蓋目標檔。POSIX 系統 rename 是原子的,讀取端永遠不會看到「半寫入」狀態。| 策略 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 無鎖 | 單執行緒、唯讀快取、日誌追加 | 效能最高 | 併發寫入資料損壞 |
| LOCK_EX (file_put_contents/fwrite+flock) | 低併發配置檔、計數器 | 簡單、跨平台 | 阻塞、NFS 不支援、高併發效能差 |
| 原子寫入 + rename | 高併發、關鍵配置、快取更新 | 無阻塞讀取、資料一致性強 | 需同檔案系統、臨時檔殘留風險 |
| 資料庫/Redis 替代 | 高頻計數、分散式環境 | 原子操作、擴展性強 | 引入外部依賴 |
LOCK_EX 不可靠:建議改用原子寫入或資料庫。FILE_APPEND 併發交錯:多進程同時追加會導致內容穿插,需加鎖或改用日誌庫(Monolog)。fwrite 分塊寫入或串流複製。is_writable 檢查:導致難以除錯的靜默失敗。dirname($file) 存在,必要時 mkdir(..., 0755, true)。<?php
use Illuminate\Support\Facades\Storage;
// 自動處理路徑、驅動器(本地/S3/ftp)、權限、原子寫入
Storage::put('config/app.json', json_encode($config));
Storage::append('logs/access.log', $logLine);
// 取得底層 Flysystem 進行進階操作
$adapter = Storage::disk('local')->getDriver()->getAdapter();
?>
日常開發首選 file_put_contents($file, $data, LOCK_EX);關鍵資料、高併發場景採用 原子寫入(臨時檔 + rename);分散式/高頻寫入遷移至 Redis/資料庫。封裝統一的 FileService 類,集中處理權限、鎖、原子性、日誌、監控,是專案長期維護的關鍵。