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

PHP 檔案寫入最佳實踐:file_put_contents、fwrite、獨佔鎖與原子寫入完整指南

     編輯:PHP 相關知識

PHP 寫入檔案的三種核心方式

根據 PHP 版本、併發需求、資料大小選擇適當寫入策略,確保資料一致性與效能。

方式一:file_put_contents(PHP 5.3+ 推薦)

<?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 相關)。

方式二:fopen/fwrite/fclose(通用、精細控制)

<?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 5.3 以下、需精細控制緩衝、或寫入大量資料分塊處理的場景。

方式三:原子寫入(寫入臨時檔 + rename,最安全)

<?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 替代高頻計數、分散式環境原子操作、擴展性強引入外部依賴

常見陷阱與避坑

  • Windows 下 LOCK_EX 不可靠:建議改用原子寫入或資料庫。
  • 追加模式 FILE_APPEND 併發交錯:多進程同時追加會導致內容穿插,需加鎖或改用日誌庫(Monolog)。
  • 大檔案一次性寫入:記憶體飆升,改用 fwrite 分塊寫入或串流複製。
  • 忽略 is_writable 檢查:導致難以除錯的靜默失敗。
  • 目錄不存在:寫入前確保 dirname($file) 存在,必要時 mkdir(..., 0755, true)。

現代框架中的檔案寫入(Laravel Storage / Flysystem)

<?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 類,集中處理權限、鎖、原子性、日誌、監控,是專案長期維護的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved