You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP fwrite替换文件行时字符长度变化引发内容异常求助

解决PHP替换TXT文件行时,新字符串过长导致后续内容被截断的问题

这问题我太熟了!你遇到的核心坑点在于**r+模式下的文件写入是字节覆盖,而非插入**。当你定位到目标行的位置后写入更长的字符串,多余的字节会直接覆盖掉下一行开头的内容,就像你看到的,第二行的N被新字符串多出来的字符给覆盖了,所以才变成02;102。

给你两种实用的解决方案,按需选择:

方案1:全文件读入内存修改(适合小文件,比如你的score.txt)

这种方式逻辑最简单,也最不容易出错,适合文件体积不大的场景:

// 读取文件所有行到数组,自动跳过空行和换行符
$lines = file("score.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$targetId = $_SESSION["id"];
$newScore = $_POST['S'];

// 遍历找到目标行并替换
foreach ($lines as &$line) {
    // 拆分每行的ID和分数
    list($currentId) = explode(';', $line);
    if ($currentId === $targetId) {
        $line = "$targetId;$newScore";
        break; // 找到后就退出循环,提升效率
    }
}
unset($line); // 记得释放引用,避免后续意外修改

// 把修改后的数组重新写入文件,每行加上换行符
file_put_contents("score.txt", implode("\n", $lines) . "\n");

方案2:临时文件逐行处理(适合大文件,避免内存占用过高)

如果你的score.txt以后可能变得很大,不想一次性把所有内容读进内存,可以用临时文件中转的方式:

$targetId = $_SESSION["id"];
$newLine = "$targetId;" . $_POST['S'] . "\n";

// 创建临时文件
$tempFilePath = tempnam(sys_get_temp_dir(), 'score_temp');
$originalHandle = fopen("score.txt", 'r');
$tempHandle = fopen($tempFilePath, 'w');

// 逐行读取原文件,修改后写入临时文件
while (($line = fgets($originalHandle)) !== false) {
    $currentId = trim(explode(';', $line)[0]);
    if ($currentId === $targetId) {
        fwrite($tempHandle, $newLine);
    } else {
        fwrite($tempHandle, $line);
    }
}

// 关闭文件句柄
fclose($originalHandle);
fclose($tempHandle);

// 替换原文件
unlink("score.txt");
rename($tempFilePath, "score.txt");

为什么原来的方法会出问题?

再给你补个原理:用r+打开文件时,文件指针停在你定位的目标行起始位置,fwrite会从这个位置开始覆盖写入字节。比如原目标行是N01;99\n(共6个字节),新字符串是N01;100\n(7个字节),多出来的1个字节就会把下一行的第一个字符N给覆盖掉,所以第二行就变成了02;102,这就是你看到的截断现象。

内容的提问来源于stack exchange,提问作者chcswt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:59:29