Есть ли эффективный и быстрый способ загрузки больших файлов json в python?

У меня есть файлы json с 500 МБ. Если я использую "тривиальный" json.загрузить свой контент сразу, он будет потреблять много памяти.

есть ли способ частично прочитать файл? Если бы это был текстовый файл с разделителями строк,я мог бы перебирать строки. Я ищу аналогию с ним.

какие предложения? Спасибо

8 ответов


короткий ответ: нет.

правильное разделение файла json потребует глубокого знания графа объектов json, чтобы получить право.

однако, если у вас есть эти знания, то вы можете реализовать файловый объект, который обертывает файл json и выплевывает правильные куски.

например, если вы знаете, что ваш файл json представляет собой один массив объектов, вы можете создать генератор, который обертывает файл json и возвращает куски массива.

вы пришлось бы сделать некоторый синтаксический анализ содержимого строки, чтобы получить фрагмент файла json правильно.

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


был дубликат этого вопроса, который имел лучший ответ. См.https://stackoverflow.com/a/10382359/1623645, что предполагает ijson.

обновление:

я попробовал, и ijson для JSON, что SAX для XML. Например, вы можете сделать следующее:

import ijson
for prefix, the_type, value in ijson.parse(open(json_file_name)):
    print prefix, the_type, value

здесь prefix является разделенным точками индексом в дереве JSON (что произойдет, если в ваших ключевых именах есть точки? Думаю, это было бы плохо. для Javascript тоже...), theType описывает саксофон-как событие, один из 'null', 'boolean', 'number', 'string', 'map_key', 'start_map', 'end_map', 'start_array', 'end_array' и value значение объекта или None если the_type событие вроде начала/окончания карту/массив.

проект имеет некоторые docstrings, но недостаточно глобальной документации. Мне пришлось покопаться в ijson/common.py найти то, что я искал.


таким образом, проблема не в том, что каждый файл слишком велик, а в том, что их слишком много, и они, похоже, складываются в памяти. Сборщик мусора Python должен быть в порядке, если вы не держите вокруг ссылок, которые вам не нужны. Трудно сказать точно, что происходит без дополнительной информации, но некоторые вещи вы можете попробовать:

  1. распределить свой код. Сделайте что-нибудь вроде:

    for json_file in list_of_files:
        process_file(json_file)
    

    Если вы пишите process_file() таким образом, что он не полагается ни на какое глобальное государство и не измените любое глобальное состояние, сборщик мусора должен иметь возможность выполнять свою работу.

  2. работа с каждым файлом в отдельном процессе. Вместо разбора всех файлов JSON сразу написать программа, которая анализирует только один и передает Каждый из них из сценария оболочки или из другого python процесс, который вызывает ваш скрипт через subprocess.Popen. Это немного менее элегантно, но если больше ничего не работает, это гарантирует, что вы не держите на устаревшие данные из одного файла в следующий.

надеюсь, что это помогает.


да.

можно использовать jsonstreamer SAX-подобный push-парсер, который я написал, который позволит вам анализировать куски произвольного размера, вы можете узнать здесь и проверьте README для примеров. Его быстро, потому что он использует библиотеку " C " yajl.


при упоминании о нехватке памяти я должен спросить, действительно ли вы управляете памятью. Вы используете ключевое слово "del"для удаления старого объекта перед попыткой прочитать новый? Python никогда не должен молча сохранять что-то в памяти, если вы удалите его.


другая идея-попытаться загрузить его в базу данных хранилища документов, такую как MongoDB. Он имеет дело с большими каплями JSON хорошо. Хотя вы можете столкнуться с той же проблемой при загрузке JSON - избегайте проблемы, загружая файлы по одному за раз.

Если path работает для вас, то вы можете взаимодействовать с данными JSON через своего клиента и потенциально не должны держать весь blob в памяти

http://www.mongodb.org/


"сборщик мусора должен освободить память"

правильно.

поскольку это не так, что-то не так. Как правило, проблема с бесконечным ростом памяти глобальных переменных.

удалить все глобальные переменные.

сделать весь код уровня модуля в меньшие функции.


в дополнение к @codeape

Я бы попытался написать пользовательский парсер json, чтобы помочь вам понять структуру JSON blob, с которым вы имеете дело. Распечатать ключ только имена, и т. д. Сделайте иерархическое дерево и решите (сами), как вы можете его разбить. Таким образом, вы можете сделать то, что предлагает @codeape - разбить файл на более мелкие куски и т. д.