在PHP中处理大型JSON文件

The*_*uck 21 php json large-files

我正在尝试处理稍大(可能高达200M)的JSON文件.该文件的结构基本上是一个对象数组.

所以有些东西:

[
  {"property":"value", "property2":"value2"},
  {"prop":"val"},
  ...
  {"foo":"bar"}
]
Run Code Online (Sandbox Code Playgroud)

每个对象都具有任意属性,并且不必与数组中的其他对象共享它们(如同,具有相同).

我想对数组中的每个对象应用处理,因为文件可能很大,我不能在内存中啜饮整个文件内容,解码JSON并迭代PHP数组.

理想情况下,我想阅读文件,获取每个对象的足够信息并进行处理.如果有类似的库可用于JSON,那么SAX类型的方法就可以了.

关于如何最好地处理这个问题的任何建议?

use*_*918 15

我已经使用基于XMLReader的api为PHP 7 编写了流式JSON拉解析器pcrov/JsonReader.

它与基于事件的解析器的不同之处在于,不是设置回调并让解析器执行其操作,而是调用解析器上的方法来移动或根据需要检索数据.找到你想要的位,想要停止解析?然后停止解析(并调用close()因为这是件好事.)

(有关pull vs基于事件的解析器的稍微更长的概述,请参阅XML读取器模型:SAX与XML pull解析器.)


例1:

从JSON中读取整个对象.

use pcrov\JsonReader\JsonReader;

$reader = new JsonReader();
$reader->open("data.json");

$reader->read(); // Outer array.
$depth = $reader->depth(); // Check in a moment to break when the array is done.
$reader->read(); // Step to the first object.
do {
    print_r($reader->value()); // Do your thing.
} while ($reader->next() && $reader->depth() > $depth); // Read each sibling.

$reader->close();
Run Code Online (Sandbox Code Playgroud)

输出:

Array
(
    [property] => value
    [property2] => value2
)
Array
(
    [prop] => val
)
Array
(
    [foo] => bar
)
Run Code Online (Sandbox Code Playgroud)

对象作为字符串键控数组返回(部分)归因于有效JSON将产生PHP对象中不允许的属性名称的边缘情况.解决这些冲突并不值得,因为贫穷的stdClass对象无论如何都不会对简单数组产生任何价值.


例2:

分别读取每个命名元素.

$reader = new pcrov\JsonReader\JsonReader();
$reader->open("data.json");

while ($reader->read()) {
    $name = $reader->name();
    if ($name !== null) {
        echo "$name: {$reader->value()}\n";
    }
}

$reader->close();
Run Code Online (Sandbox Code Playgroud)

输出:

property: value
property2: value2
prop: val
foo: bar
Run Code Online (Sandbox Code Playgroud)

例3:

阅读给定名称的每个属性.额外奖励:从字符串而不是URI读取,加上从同一对象中具有重复名称的属性获取数据(在JSON中允许,这有多么有趣.)

$json = <<<'JSON'
[
    {"property":"value", "property2":"value2"},
    {"foo":"foo", "foo":"bar"},
    {"prop":"val"},
    {"foo":"baz"},
    {"foo":"quux"}
]
JSON;

$reader = new pcrov\JsonReader\JsonReader();
$reader->json($json);

while ($reader->read("foo")) {
    echo "{$reader->name()}: {$reader->value()}\n";
}

$reader->close();
Run Code Online (Sandbox Code Playgroud)

输出:

foo: foo
foo: bar
foo: baz
foo: quux
Run Code Online (Sandbox Code Playgroud)

如何最好地阅读您的JSON取决于它的结构以及您想要用它做什么.这些例子应该给你一个开始的地方.


The*_*uck 14

我决定开发一个基于事件的解析器.它还没有完成,当我推出一个令人满意的版本时,我会用一个链接来编辑我的工作.

编辑:

我终于找到了一个我满意的解析器版本.它可以在GitHub上找到:

https://github.com/kuma-giyomu/JSONParser

可能还有一些改进空间,欢迎提供反馈.


Fil*_*axa 6

最近我制作了一个名为 JSON Machine 的库,它可以有效地解析不可预测的大 JSON 文件。使用方法很简单foreach。我自己将它用于我的项目。

例子:

foreach (JsonMachine::fromFile('employees.json') as $employee) {
    $employee['name']; // etc
}
Run Code Online (Sandbox Code Playgroud)

请参阅https://github.com/halaxa/json-machine