PHP从一个数组创建多个给定大小的json文件

标签 php arrays

我想从一个数组创建多个 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()将您的数组切割成 block ,当 json_encoded 时,将接近预期的大小。让我们看一下您的数组中的一个样本:

string(58) "{"category":"1795","email":null,"level":1,"name":"BARFOO"}"

这里的“名称”似乎是唯一可能变化更显着的名称。让我们将其平均为 12 个字符,每个项目的字符串长度为 64 个字节。然后,您可以将其中的 78125 个放入 5MB 中。为了将其保持在标记之下,我们将其设为 75000。然后,$chunks = array_chunk($data, 75000) 将为您提供 X block 大约或略低于 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 执行双重任务,但 block 大小不会受到源数据差异的影响。我为 50000 字节的 block 运行了上面的测试脚本,您需要 5000000 代替您的用例。我生成的虚拟数据分成整齐的 50K block ,最大。一组的 +/- 大小,加上最后一个文件中的余数。

在考虑这个问题的同时,我也考虑过使用 strlen(implode(为了获得准确的 JSON 字符串大小而进行权衡,这将是一个很大的惩罚。

无论如何,一旦 block 准备好,我们需要做的就是把它们写起来:

foreach($chunks as $n => $chunk) {
    $json = json_encode($chunk);
    file_put_contents("tmp/chunk_{$n}.json", $json);
}

...或匹配您的 block 命名和目录架构。

也许有更聪明的方法可以做到这一点。也就是说,据我所知,核心 PHP 中的任何内容都不会执行这种开箱即用的操作(即使对于 vanilla 数组也是如此),并且上述内容应该执行得相当好。请记住有足够的可用内存。 :)

附:在计算大小时,我们为每个项目添加 +1,代表 {}、{}、{} 或对象分隔符。严格来说,您还需要在总计中加上 +2,因为它将是 [{},{},{}],而我们只计算每个的长度数组项作为单独的 JSON 对象。使用其他数据结构,您的补偿里程可能会有所不同。


优化更新:如果您选择“精确大小”方法并希望优化内存使用,最好将 JSON 提交集成到分 block 循环中。 (感谢@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) 调用,取消初始数组并释放内存。 CPU 方面,这两个选项之间没有显着差异。

也可以在每次添加到 $chunk[] 后清除 $data 数组的成员,但是在 5MB block 大小时,这里的内存优势可以忽略不计。初始数组本身的加载/定义是昂贵的,是最大内存使用数字的主要因素。 (在开始任何处理之前,我使用的测试数组占用了 29.25 MB。)

关于PHP从一个数组创建多个给定大小的json文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63381465/

相关文章:

arrays - 使用静态范围最小查询维护的数组中单个更改的复杂性

javascript - 将对象数组中两个属性的唯一值存储到单个数组中

php - 如何使用 htaccess 避免 php 中同一文件的多个路径?

php - 如何使用 PHP 循环遍历按十年分组的记录的 MySQL 结果集?

java - PHP调用Java过程的性能调优

ruby - 使用 ruby​​ mechanize 遍历 html 元素

java - 数组创建堆栈溢出

php - 通过php中的POST具有相同名称的多个输入

php - 是否有用于 PHP 的 iCalendar 文件的现有解析器?

php - 使用 JavaScript 获取 POST 值