Добавить в список словаря, загруженного в json, без загрузки списка с помощью python

#python #json

Вопрос:

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

например, у .json меня есть

 [{'a': 1}]
 

Можно ли добавить {'b', 2} в список .json таким образом, чтобы файл стал

 [{'a': 1}, {'b', 2}]
 

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

Редактировать:

PS: Я также открыт для другого формата файлов, если он может эффективно хранить большой список словарей и может выполнять описанную выше функцию

Комментарии:

1. Формат JSON для этого не подходит. Взгляните на jsonlines .

2. Что вы подразумеваете под » без явного чтения загрузите полный список, добавьте, а затем снова сбросьте список «? У вас был сохраненный список в файле, и вы не хотите читать этот файл?

3. @Kshitiz Хорошо, я могу прочитать файл, но я пытаюсь избежать чтения всего списка ( json.load() в переменную, которая может занять большой объем памяти)

4. Если бы вы попытались просто открыть файл notepad и написать. Извините, но я не уверен, что вы находитесь в Windows или другой операционной системе. Но если файл большой и вы просто хотите добавить только 2/3 вещей, то вы можете попробовать. Я не уверен, что это сработает или нет, поэтому я не публикую это в качестве ответа, пожалуйста, сообщите мне об этом после попытки!

Ответ №1:

Похоже, что при правильных обстоятельствах это может быть простой проблемой с обработкой файлов. Если вы уверены, что корневая структура данных дампа действительно представляет собой массив json, вы можете удалить последнее «]» в файле, а затем добавить в файл новый дамп.

Вы можете добавить его с помощью функции dumps.

 from json import dumps, dump
import os

#This represents your current dump call
with open('out.json', 'w') as f:
    dump([{'version':1}], f)

# This removes the final ']'
with open('out.json', 'rb ') as f:
    f.seek(-1, os.SEEK_END)
    f.truncate()

#This appends the new dictionary
with open('out.json', 'a') as f:
    f.write(',')
    f.write(dumps({'n':1}))
    f.write(']')
 

Похоже, это также работает, если вы сбрасываете данные с отступом, потому что функция сброса в любом случае не заканчивается символом новой строки.

Обработка пустого массива

Если при первом сбросе списка он был пуст, в результате чего в файле «[] «появился пустой массив json, то добавление запятой, как в моем примере, приведет к чему-то вроде» [,…], чего вы, вероятно, не хотите.

То, как я видел, как это обрабатывается в дикой природе протоколами, такими как i3bar (которые используют бесконечный массив json для отправки информации), всегда начинается с элемента заголовка. В их случае они используют { "version": 1 } .

Поэтому убедитесь, что у вас это есть в начале вашего списка, когда вы делаете первый сброс, то есть, если вы не уверены, что у вас всегда будет что-то в списке.

Другие примечания

Несмотря на то, что такой ручной взлом json используется в таких проектах, как i3bar, я бы лично не рекомендовал делать это в производственной среде.

Ответ №2:

JSON требует, чтобы список был закрыт с помощью a "]" , поэтому он изначально не является приложением. Вы можете попробовать что-то хитрое, открыв конец файла, удалив»]», а также поработать с новым JSON, который вы пытаетесь написать. Но это грязно.

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

 def append_dict(filename, d):
    with open(filename, 'a', encoding='utf-8') as fp:
        fp.write(json.dumps(d))
        fp.write("n")

def read_list(filename):
    with open(filename, encoding='utf-8') as fp:
        return [json.loads(line) for line in fp]
 

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

Комментарии:

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