2016-03-22 2 views
3

Я пишу программу, которая требует от меня создания очень большого файла json. Я знаю, что традиционный способ состоит в том, чтобы сбрасывать список словарей с помощью json.dump(), но список просто слишком велик, что даже общее пространство памяти + подкачки не может удерживать его до того, как оно будет сброшено. Есть ли способ передать его в файл json, то есть записать данные в файл json поэтапно?Как поэтапно писать в json-файл

+0

Вы можете вставить '[' в начале файла, а затем написать дамп каждого требуемого значения в качестве нового элемента массива. Когда вы закрываете файл, завершите его с помощью ']'. –

ответ

2

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

Это явно будет очень большой файл - было бы более подходящим другое представление?

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

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

+0

Форматирование не имеет значения. Файл json используется для индексации большой коллекции документов в Apache Solr. Я обязательно попробую ваш метод, а затем проверю его правильно, если он работает. Спасибо! – fanchyna

2

Я знаю, что это год спустя, но проблема все еще открыта, и я удивлен, что json.iterencode() не упоминался.

Потенциальная проблема с iterencode в этом примере заключается в том, что вы хотите иметь итеративный дескриптор большого набора данных с помощью генератора, а json encode не сериализует генераторы.

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

Ниже приведен пример подкласса этого списка.

class StreamArray(list): 
    """ 
    Converts a generator into a list object that can be json serialisable 
    while still retaining the iterative nature of a generator. 

    IE. It converts it to a list without having to exhaust the generator 
    and keep it's contents in memory. 
    """ 
    def __init__(self, generator): 
     self.generator = generator 
     self._len = 1 

    def __iter__(self): 
     self._len = 0 
     for item in self.generator: 
      yield item 
      self._len += 1 

    def __len__(self): 
     """ 
     Json parser looks for a this method to confirm whether or not it can 
     be parsed 
     """ 
     return self._len 

Использование здесь очень простое. Получите дескриптор генератора, передайте его в класс StreamArray, передайте объект массива потоков в iterencode() и переберите куски. Чанки будут обработанными json-выходом, которые могут быть непосредственно записаны в файл.

Пример использования:

#Function that will iteratively generate a large set of data. 
def large_list_generator_func(): 
    for i in xrange(5): 
     chunk = {'hello_world': i} 
     print 'Yielding chunk: ', chunk 
     yield chunk 

#Write the contents to file: 
with open('/tmp/streamed_write.json', 'w') as outfile: 
    large_generator_handle = large_list_generator_func() 
    stream_array = StreamArray(large_generator_handle) 
    for chunk in json.JSONEncoder().iterencode(stream_array): 
     print 'Writing chunk: ', chunk 
     outfile.write(chunk) 

Выходной сигнал, который показывает выход и записывает произойти последовательно.

Yielding chunk: {'hello_world': 0} 
Writing chunk: [ 
Writing chunk: { 
Writing chunk: "hello_world" 
Writing chunk: : 
Writing chunk: 0 
Writing chunk: } 
Yielding chunk: {'hello_world': 1} 
Writing chunk: , 
Writing chunk: { 
Writing chunk: "hello_world" 
Writing chunk: : 
Writing chunk: 1 
Writing chunk: } 
Смежные вопросы