php - PHP从一个数组创建多个给定大小的json文件
问题描述
我想从一个数组创建多个 json 文件(file1.json、file2.json 等),并且每个文件的最大文件大小必须为 5 mb。
我有这种数组:
array (
0 => array (
'category' => '179535',
'email' => NULL,
'level' => 1,
'name' => 'FOO'
),
1 => array (
'category' => '1795',
'email' => NULL,
'level' => 1,
'name' => 'BARFOO'
),
2 => array (
'category' => '16985',
'email' => NULL,
'level' => 1,
'name' => 'FOOBAR'
),
....
25500 => array (
'category' => '10055',
'email' => NULL,
'level' => 1,
'name' => 'FOOBARBAR'
)
)
如果我用 json_encode($arr) 将它写在一个文件中。生成的文件大约为 85mb。那么如何拆分此数组以使每个文件最大为 5 mb?
解决方案
假设您的数据是合理对称的,对性能最友好的选项是简单地使用array_chunk()
将您的数组切割成块,当json_encode
d 时,将接近预期的大小。让我们看一下您的数组中的一个样本:
string(58) "{"category":"1795","email":null,"level":1,"name":"BARFOO"}"
这里的“名称”似乎是唯一可能变化更显着的名称。让我们将其平均为 12 个字符,每个项目的字符串长度为 64 个字节。然后,您可以将其中的 78125 个放入 5MB 中。为了保持它在标记之下,让我们将它设为 75000。然后,$chunks = array_chunk($data, 75000)
会给你 X 块大约或略低于 5MB 标记。
现在,如果您想要更精确,并且尺寸真的很重要……我们可以:
$size = 0; // size counter
$chunkno = 1; // chunk number
$maxbytes = 50000; // 50000-byte chunks
$chunks = []; // for array chunks
foreach($data as $set) {
// if over the limit, move on to next chunk
if ($size > $maxbytes) {
$size = 0;
$chunkno++;
}
$size += strlen(json_encode($set)) + 1; // add a comma's length!
$chunks[$chunkno][] = $set;
}
// unset($data); // in case you have memory concerns
在这里,我们显然对 json_encode 执行双重任务,但块大小不会受到源数据差异的影响。我为 50000 字节的块运行了上面的测试脚本,你会希望有5000000
你的用例。我生成的虚拟数据分成整齐的 50K 块,最大。一组的 +/- 大小,加上最后一个文件中的其余部分。
在考虑这一点的同时,我也考虑了这样做的想法strlen(implode(
,但鉴于 PHP 的总体性能很好json_encode
,应该不会有太多的惩罚,因为要权衡获取确切的 JSON 字符串大小。
无论如何,一旦块准备好,我们需要做的就是把它们写下来:
foreach($chunks as $n => $chunk) {
$json = json_encode($chunk);
file_put_contents("tmp/chunk_{$n}.json", $json);
}
...或匹配您的块命名和目录架构可能是什么。
也许有更聪明的方法可以做到这一点。也就是说,据我所知,核心 PHP 中的任何内容都不会执行这种开箱即用的操作(即使对于 vanilla 数组也是如此),并且上述内容应该执行得相当好。请记住有足够的可用内存。:)
PS 在计算大小时,我们为每个项目加上 +1,代表{},{},{}
,或对象分隔符。严格来说,您还希望将 +2 添加到总计中,因为它将是[{},{},{}]
,而我们只是将每个数组项的长度计算为单独的 JSON 对象。使用其他数据结构,您的补偿里程可能会有所不同。
优化更新:如果您选择“精确大小”方法并希望优化内存使用,最好将 JSON 提交集成到分块循环中。(感谢@NigelRen 的建议。)如下(其他初始变量如前):
$chunk = [];
foreach($data as $n => $set) {
if ($size > $maxbytes) {
file_put_contents("tmp/chunk_{$chunkno}.json", json_encode($chunk));
$chunk = [];
$chunkno++;
$size = 0;
}
$size += strlen(json_encode($set)) + 1;
$chunk[] = $set;
// unset($data[$n]); // in case of memory issues, see notes
}
如果您对影响感到好奇。使用这种方法,内存使用量达到(已使用,最大)1.06 MB、29.34 MB。使用单独的写入例程,26.29 MB,31.8 MB。这两个数字都包括unset($data)
调用、nixing 初始数组和释放内存。CPU 方面,这两个选项之间没有显着差异。
也可以在$data
每次添加到 后清除数组的成员$chunk[]
,但是在 5MB 块大小时,这里的内存优势可以忽略不计。初始数组本身的加载/定义是昂贵的,是最大内存使用数字的主要因素。(在开始任何处理之前,我使用的测试数组占用了 29.25 MB。)
推荐阅读
- sql-server - 如何将所有行合并为一个?
- r - 需要帮助创建基于 R 中其他三列的计算的列
- tensorflow - Jetson NX optimize tensorflow model using TensorRT
- azure - Fetch api not posting data to backend server
- python - Plot RGB image with matshow failed - Invalid shape
- kubernetes-helm - Installing nextcloud (helm) on linode k8s (v1.19) cluster with nginx-ingress tls/ssl encryption (let's encrypt) dosen't work as expected
- lotus-notes - Button in Lotus Notes that automatically forwards en email with attachment
- wordpress - 如何在 WooCommerce 中复制产品属性变化
- logging - 如何使用 spring-data-aerospike 记录 aerospike 查询
- docker - 将超级账本结构部署到 docker swarm