Обработка больших файлов JSON в PHP - PullRequest
21 голосов
/ 29 октября 2010

Я пытаюсь обработать несколько больших (возможно, до 200 МБ) файлов JSON.Структура файла в основном представляет собой массив объектов.

Таким образом, что-то вроде:

[
  {"property":"value", "property2":"value2"},
  {"prop":"val"},
  ...
  {"foo":"bar"}
]

Каждый объект имеет произвольные свойства и не обязательно обмениваться ими с другими объектами вмассив (как в случае, имея то же самое).

Я хочу применить обработку к каждому объекту в массиве, и поскольку файл потенциально огромен, я не могу вылить все содержимое файла в память, декодируя JSON иперебираем массив PHP.

Так что в идеале я хотел бы прочитать файл, получить достаточно информации для каждого объекта и обработать его.Подход типа SAX был бы в порядке, если бы существовала подобная библиотека, доступная для JSON.

Любое предложение о том, как лучше всего решить эту проблему?

Ответы [ 6 ]

15 голосов
/ 09 сентября 2016

Я написал потоковый синтаксический анализатор JSON pcrov / JsonReader для PHP 7 с API на основе XMLReader .

Он значительно отличается от событийногосинтаксические анализаторы в этом, вместо того, чтобы устанавливать обратные вызовы и позволять анализатору делать свое дело, вы вызываете методы анализатора для перемещения вперед или извлечения данных по желанию.Нашли нужные вам биты и хотите прекратить разбор?Затем прекратите синтаксический анализ (и вызовите close(), потому что это хорошо.)

(Для более длинного обзора парсеров, основанных на событиях по сравнению с событиями, см. Модели чтения XML: SAX противXML pull parser .)


Пример 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();

Вывод:

Array
(
    [property] => value
    [property2] => value2
)
Array
(
    [prop] => val
)
Array
(
    [foo] => bar
)

Объекты возвращаются в виде массивов со строковыми ключами из-за (частично) крайних случаев, когда действительный 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();

Вывод:

property: value
property2: value2
prop: val
foo: bar

Пример 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();

Вывод:

foo: foo
foo: bar
foo: baz
foo: quux

Как лучше всего прочитать ваш JSON, зависит от его структуры и того, что вы хотите с ним делать.Эти примеры должны дать вам место для начала.

14 голосов
/ 03 ноября 2010

Я решил поработать над анализатором событий. Это еще не сделано, и я отредактирую вопрос со ссылкой на мою работу, когда я выложу удовлетворительную версию.

EDIT:

Я наконец-то разработал версию парсера, которой я доволен. Он доступен на GitHub:

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

Возможно, есть место для некоторых улучшений, и я рад приветствовать вас.

2 голосов
/ 14 марта 2015

Это простой потоковый анализатор для обработки больших документов JSON. Используйте его для анализа очень больших JSON-документов, чтобы избежать загрузки всего содержимого в память, как работает практически любой другой JSON-анализатор для PHP.

https://github.com/salsify/jsonstreamingparser

2 голосов
/ 29 октября 2010

Существует что-то подобное, но только для C ++ и Java . Если вы не можете получить доступ к одной из этих библиотек из PHP, в PHP нет реализации для этого, но json_read(), насколько я знаю. Однако, если json структурирован так просто, легко просто прочитать файл до следующего } и затем обработать JSON, полученный через json_read(). Но вам лучше сделать это в буфере, например, прочитать 10 КБ, разделить на}, если не найдено, прочитать еще 10 КБ и обработать найденные значения. Затем прочитайте следующий блок и так далее.

1 голос
/ 29 ноября 2018

Недавно я создал библиотеку под названием JSON Machine, которая эффективно анализирует непредсказуемо большие файлы JSON. Использование через простой foreach. Я сам использую его для своего проекта.

Пример:

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

См. https://github.com/halaxa/json-machine

0 голосов
/ 29 октября 2010

Есть http://github.com/sfalvo/php-yajl/ Я сам им не пользовался.

...