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

PHP 精準替換文本文件指定行:explode/implode 實戰與大文件優化方案

     編輯:PHP 相關知識

核心需求

運維腳本、配置管理、日誌清洗等場景常需「讀取文本文件 → 修改第 N 行 → 寫回」。PHP 無原生「隨機行寫入」函數,經典做法是「全量讀入 → 分割數組 → 修改 → 合併寫回」。

基礎實現(適用小文件)

$filePath = '123.txt';
$content  = file_get_contents($filePath);

// 1. 按換行符分割為數組(兼容 \r\n / \n / \r)
$lines = preg_split('/\R/', $content); // PHP 7+ 推薦
// 兼容舊版:$lines = explode("\n", $content); // 僅按 \n 分割,行尾可能殘留 \r

// 2. 替換指定行(索引從 0 開始,第 13 行對應 [12])
if (isset($lines[12])) {
    $lines[12] = '123'; // 新內容
} else {
    // 行號超出範圍:可選擇擴展數組或拋出異常
    $lines[12] = '123';
}

// 3. 合併回字符串並寫入
$newContent = implode("\n", $lines); // 統一用 \n 存儲,跨平台兼容性最好
file_put_contents($filePath, $newContent);

關鍵細節解析

1. 換行符分割策略

  • preg_split('/\R/'):匹配所有 Unicode 換行序列(\r\n、\n、\r、\f 等),PHP 7.0+ 可用,最健壯。
  • explode("\n"):舊版常用,但 Windows \r\n 下會殘留 \r 在行尾,後續處理需 rtrim($line, "\r")。

2. 索引越界處理

若目標行號大於現有行數,上述代碼會自動在中間插入空行(PHP 數組自動擴展)。若需「僅修改現有行,不存在則報錯」,請加判斷:

if (!isset($lines[$targetIndex])) {
    throw new OutOfBoundsException("行號 $targetLine 不存在");
}

3. 編碼一致性

讀取、寫入均建議顯式指定編碼,避免中文亂碼:

$content = file_get_contents($filePath);
// 若文件為 GBK,需轉碼:$content = mb_convert_encoding($content, 'UTF-8', 'GBK');
// ... 處理 ...
file_put_contents($filePath, $newContent); // 寫入時保持 UTF-8

大文件優化方案(內存安全)

若文件超過百 MB,file_get_contents 會佔用大量內存甚至 OOM。改用「流式讀寫 + 臨時文件」:

$src = 'big.log';
$dst = $src . '.tmp';
$targetLine = 10000; // 要修改的行號(1-based)
$newLineContent = 'REPLACED CONTENT';

$fpIn  = fopen($src, 'r');
$fpOut = fopen($dst, 'w');
$lineNo = 0;

while (($line = fgets($fpIn)) !== false) {
    $lineNo++;
    if ($lineNo === $targetLine) {
        fwrite($fpOut, $newLineContent . "\n");
    } else {
        fwrite($fpOut, $line);
    }
}
fclose($fpIn);
fclose($fpOut);

// 原子替換(防止讀取時文件損壞)
rename($dst, $src);

優勢: 內存佔用恆定(僅緩衝區)、支援超大文件、rename 原子性保證並發安全。

進階封裝:可復用函數

/**
 * 替換文本文件指定行
 * @param string $filePath 文件路徑
 * @param int $lineNum 目標行號(1-based)
 * @param string $newContent 新行內容(不含換行符)
 * @param string $encoding 文件編碼,默認 UTF-8
 * @return bool 成功返回 true,行號越界返回 false
 */
function replaceFileLine(string $filePath, int $lineNum, string $newContent, string $encoding = 'UTF-8'): bool {
    if ($lineNum < 1) return false;
    
    $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    // file() 自動處理換行符,返回數組;FLAGS 去除行尾換行符並跳過空行(視業務決定是否保留 SKIP_EMPTY_LINES)
    
    if ($lineNum > count($lines)) return false;
    
    $lines[$lineNum - 1] = $newContent;
    return (bool) file_put_contents($filePath, implode("\n", $lines));
}

總結

場景推薦方案核心函數
小文件(< 10MB)、簡單腳本全量讀入 + preg_split/爆炸 + implodefile_get_contents, preg_split, implode, file_put_contents
中大文件、長期運行服務流式讀寫 + 臨時文件 + rename 原子替換fopen, fgets, fwrite, fclose, rename
需要保留原文件格式(編碼、換行符)二進制模式 'rb'/'wb' + 不做編碼轉換fopen($f, 'rb'), fwrite 不轉碼

掌握「全量法」與「流式法」兩套招式,即可應對 99% 的文本行替換需求。記住:小文件圖簡潔,大文件守內存,編碼統一用 UTF-8,原子寫入防併發。

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