当前位置: 首页 > news >正文

PHP 高效 JSON 库 JsonMachine

在现代软件开发和物联网(IoT)应用中,JSON 已经无处不在。无论是设备状态上报、传感器数据采集,还是服务器端 API 通信,几乎所有系统都在 读写 JSON

然而,随着数据量激增,JSON 文件也变得越来越大,几十 MB、几百 MB,甚至上 GB 的日志或状态文件,直接使用PHP的传统方法读取的话,如:
json_decode(file_get_contents(...)) 很容易就会 直接爆内存

Allowed memory size of __你心中的数字__ bytes exhausted

如果你还在为处理大 JSON 文件而头疼,不妨看看 JsonMachine。这个 PHP 库能让你 边解析边遍历 JSON,低内存、高效率,从此大文件也能轻松处理。

核心特点

  1. 1. 低内存占用

    • • 每次只解析一个 JSON 项目,而不是一次性把整个 JSON 加载到内存。

    • • 文件/流处理内存复杂度 O(2),字符串解析内存复杂度 O(n+1)

  2. 2. 易用

    • • 直接用 foreach 遍历 JSON,支持对象和数组。

    • • 可以迭代任意子树或标量值。

  3. 3. 支持 JSON Pointer

    • • 可以指定 /results/-/color 等指针,仅迭代子节点或特定字段。

  4. 4. 递归迭代

    • • RecursiveItems 支持多层嵌套 JSON 的递归遍历。

  5. 5. 可选解码器

    • • 默认使用 ExtJsonDecoder(基于 json_decode

    • • 可用 PassThruDecoder 或 ErrorWrappingDecoder 处理特殊需求或跳过错误项。

  6. 6. 进度追踪

    • • 开启 debug 后可通过 getPosition() 获取解析字节位置,计算百分比。

快速安装

composer require halaxa/json-machine

基本使用

1. 遍历整个 JSON 文件

use JsonMachine\Items;$users = Items::fromFile('big_8m.json');
foreach ($users as $id => $user) {var_dump($user->name);
}

2. 遍历子树(JSON Pointer)

$fruits = Items::fromFile('big_8m.json', ['pointer' => '/results']);
foreach ($fruits as $name => $data) {echo "$name => {$data->color}\n";
}

3. 遍历数组嵌套值

$colors = Items::fromFile('big_8m.json', ['pointer' => '/results/-/color']);
foreach ($colors as $color) {echo $color, "\n"; // red, yellow
}

4. 获取单个标量值

$lastModified = Items::fromFile('big_8m.json', ['pointer' => '/lastModified']);
echo iterator_to_array($lastModified)['lastModified'];

5. 递归迭代复杂嵌套 JSON

use JsonMachine\RecursiveItems;$users = RecursiveItems::fromFile('big_8m.json');
foreach ($users as $user) {foreach ($user['friends'] as $friend) {$friendArray = $friend->toArray();echo $friendArray['username'];}
}

6. 处理大文件或流

$stream = fopen('big_8m.json', 'r');
$items = Items::fromStream($stream);

7. 跳过错误项

use JsonMachine\JsonDecoder\ErrorWrappingDecoder;
useJsonMachine\JsonDecoder\ExtJsonDecoder;$items = Items::fromFile('big_8m.json', ['decoder' => newErrorWrappingDecoder(newExtJsonDecoder())
]);
foreach ($itemsas$item) {if ($iteminstanceof \JsonMachine\JsonDecoder\DecodingError) continue;// 正常处理
}

简单测试

以下是笔者亲测试的数据示例,先使用generator_json.php生成了800万条数据,然后使用传统的json_decode方法和JsonMachine库进行对比,如下:

1. 生成JSON 数据

<?php$startTime = microtime(true); // 开始计时$filename = 'big_8m.json';
$handle = fopen($filename, 'w');if (!$handle) {die("无法打开文件 $filename");
}// 写入 JSON 数组的起始符
fwrite($handle, '[');$total = 8000000;   // 800万条
$first = true;for ($i = 1; $i <= $total; $i++) {$item = ['id' => $i,'name' => "User$i",'email' => "user$i@example.com",'phone' => "1234567890$i",];$json = json_encode($item);if ($first) {fwrite($handle, $json);$first = false;} else {fwrite($handle, ',' . PHP_EOL . $json);}
}fwrite($handle, ']'); // 写入 JSON 数组结束符
fclose($handle);$endTime = microtime(true); // 结束计时
$duration = $endTime - $startTime;echo"生成完成,文件路径:$filename\n";
echo"耗时:".round($duration, 2)." 秒\n";

图片

2. 传统的json_decode方法

<?phpini_set('memory_limit', '4G'); // 设置内存上限为 4GB$file = __DIR__ . '/big_8m.json';$startTime = microtime(true);
$startMemory = memory_get_usage();// 直接一次性读取整个文件
$json = file_get_contents($file);
$data = json_decode($json, true); // 转为数组$endTimeDecode = microtime(true);
$memoryAfterDecode = memory_get_usage();
$peakMemory = memory_get_peak_usage(true);$count = count($data);// 输出前 5 条,避免屏幕太长
for ($i = 0; $i < min(5, $count); $i++) {echo$data[$i]['id'] . ' => ' . $data[$i]['name'] . PHP_EOL;
}$endTime = microtime(true);
$endMemory = memory_get_usage();echo PHP_EOL;
echo"总记录数:$count" . PHP_EOL;
echo"耗时(读取+解析):". round($endTimeDecode - $startTime, 2) ." 秒" . PHP_EOL;
echo"总耗时:". round($endTime - $startTime, 2) ." 秒" . PHP_EOL;
echo"起始内存:" . round($startMemory / 1024 / 1024, 2) . " MB" . PHP_EOL;
echo"解析后内存:" . round($memoryAfterDecode / 1024 / 1024, 2) . " MB" . PHP_EOL;
echo"结束内存:" . round($endMemory / 1024 / 1024, 2) . " MB" . PHP_EOL;
echo"峰值内存:" . round($peakMemory / 1024 / 1024, 2) . " MB" . PHP_EOL;

图片

3. 使用JsonMachine库

<?php$startTime = microtime(true); // 开始计时
$startMemory = memory_get_usage();require'vendor/autoload.php';
useJsonMachine\Items;$items = Items::fromFile(__DIR__ . '/big_8m.json');foreach ($itemsas$item) {// 对象访问echo$item->id . ' => ' . $item->name . PHP_EOL;
}$endTime = microtime(true); // 结束计时
$duration = $endTime - $startTime;$endMemory = memory_get_usage();
$peakMemory = memory_get_peak_usage(true);echo" === 耗时:".round($duration, 2)." 秒" . PHP_EOL;
echo" === 起始内存:" . round($startMemory / 1024 / 1024, 2) . " MB" . PHP_EOL;
echo" === 结束内存:" . round($endMemory / 1024 / 1024, 2) . " MB" . PHP_EOL;
echo" === 峰值内存:" . round($peakMemory / 1024 / 1024, 2) . " MB" . PHP_EOL;

图片

写在最后

在 PHP 开发中,处理大 JSON 文件时,推荐使用 JsonMachine,它支持流式解析,一次只加载一个 JSON 项到内存,内存占用恒定,代码简单易用,并且可以遍历子树、递归解析或跳过错误项。虽然也可以使用 fgetc 等流式方式手动处理,但实现起来非常麻烦,容易出错。千万不要直接使用传统的
json_decode(file_get_contents('big_8m.json'), true)方法,因为这种方式会一次性把整个文件读入内存,遇到几十 MB、几百 MB 或更大的文件很容易导致内存爆炸。总之,大 JSON 文件优先用 JsonMachine,手动解析可行但不推荐,绝对避免一次性加载整个文件。

http://www.dtcms.com/a/499283.html

相关文章:

  • 网站建设内部因素百度站长平台有哪些功能
  • Linux内核IPoIB驱动深度解析:在InfiniBand上跑IP网络的高性能之道
  • 275TOPS算力边缘计算盒子的价值洞察与市场定位---视程空间
  • 对话 MoonBit 张宏波:为 AI 重构编程语言
  • QGIS制图专题4:缓冲区分析与服务半径专题图制作
  • IP 资源会枯竭吗?IPv6 能解决代理市场的矛盾吗?
  • 物联网运维中的边缘计算任务调度优化策略
  • TensorFlow2 Python深度学习 - 循环神经网络(LSTM)示例
  • C++第二十三课:猜数字游戏等练习
  • 河南省建设厅网站中州杯企业网站推广怎么做
  • 【数论】最大公因数 (gcd) 与最小公倍数 (lcm)
  • rocky linux MariaDB安装过程
  • git的 Rebase
  • 第8篇 QT联合halcon12在vs2019搭建环境开发图像处理
  • 【小白笔记】最大交换 (Maximum Swap)问题
  • CentOS安装Node.js
  • 深入解析MCP:从基础配置到高级应用指南
  • 佛山网站建设服务wordpress 不能更换主题
  • Process Monitor 学习笔记(5.13):从 0 到 1 的排障剧本清单(可复用模板)
  • Fluent 重叠网格+UDF NACA0012翼型摆动气动仿真
  • 深圳网站建设 设计卓越迈wordpress一键采集文章
  • 理想汽车Java后台开发面试题及参考答案(下)
  • python|if判断语法对比
  • 全链路智能运维中的实时流处理架构与状态管理技术
  • 排序算法:详解快速排序
  • 安阳哪里做360网站科技感十足的网站
  • UV 紫外相机在半导体制造领域的应用
  • 突破亚微米光电子器件制造瓶颈!配体交换辅助打印技术实现全打印红外探测器
  • 可见光工业相机半导体制造领域中的应用
  • require和 import是两种不同的模块引入方式的区别