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

PHP使用LOCK_EX读写JSON文件时出现损坏及json_decode失败问题排查

问题分析与修复:PHP修改JSON文件时的损坏与解析失败问题

嘿,我来帮你排查这个问题——你的代码第一次运行正常,但后续调用就出问题了,核心问题出在文件指针位置处理和不完整的内容读取上,具体拆解如下:

核心问题拆解

  • fgets仅读取单行内容:你的初始JSON是单行的,fgets刚好能读完整,但如果后续写入的JSON变成多行(比如不小心开启了JSON_PRETTY_PRINT),或文件混入换行符,fgets只会读取第一行,拿到不完整的JSON字符串,直接导致json_decode返回false。
  • 文件指针未重置,写入产生空字节:这是最致命的点:
    1. 用r+模式打开文件,第一次读取fgets后,指针已经移动到文件末尾;
    2. ftruncate($fh, 0)会把文件截断到0长度,但PHP的ftruncate不会改变指针位置,指针仍停留在原文件末尾;
    3. 此时调用fwrite,会从指针当前位置开始写入,导致文件开头出现大量空字节(\0);
    4. 第二次调用代码时,fgets读取到带空字节的字符串,json_decode无法解析,后续修改写入会彻底破坏文件。
  • 缺少错误检查:没有对fopen、flock、json_decode等关键操作的返回值做校验,出错后继续执行,进一步加剧文件损坏。

修复后的代码

我调整了代码,解决了上述所有问题,还加了必要的错误处理:

<?php
define('PATH_TO_FILE', './test.json');

$fh = fopen(PATH_TO_FILE, "r+");
if (!$fh) {
    die("无法打开目标文件");
}

// 确保获取排他锁,处理锁获取失败的情况
if (!flock($fh, LOCK_EX)) {
    fclose($fh);
    die("无法获取文件排他锁,请稍后重试");
}

// 重置指针到文件开头,读取完整内容
fseek($fh, 0);
$data = fread($fh, filesize(PATH_TO_FILE));
$jsonData = json_decode($data, true);

// 检查JSON解析是否成功
if ($jsonData === null) {
    flock($fh, LOCK_UN);
    fclose($fh);
    die("JSON解析失败,文件内容可能已损坏");
}

// 修改数据
$jsonData['mod_1'] = 1;
$dataWrite = json_encode($jsonData);

// 重置指针到开头,截断文件后写入
fseek($fh, 0);
if (!ftruncate($fh, 0)) {
    flock($fh, LOCK_UN);
    fclose($fh);
    die("无法截断文件");
}

fwrite($fh, $dataWrite);
// 强制将缓冲区内容写入磁盘,避免数据丢失
fflush($fh);

// 释放锁并关闭文件
flock($fh, LOCK_UN);
fclose($fh);
clearstatcache();
?>

修复点说明

  • 读取完整文件内容:用fread配合filesize读取整个文件,代替fgets,确保拿到完整的JSON字符串,不受换行影响。
  • 强制重置文件指针:每次读取、写入前都用fseek($fh, 0)把指针定位到文件开头,彻底避免指针位置错误导致的空字节问题。
  • 添加错误检查:对每个关键操作的返回值做判断,一旦出错立即释放锁、关闭文件并终止执行,防止进一步破坏文件。
  • 添加fflush:强制将缓冲区内容写入磁盘,避免因程序意外退出导致数据丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:59:27