2016-04-21 2 views
0

У меня есть следующие данные в моей JSON файл:Читать словарь JSON верхнего уровня пошагово с помощью Python ijson

{ 
    "first": { 
     "name": "James", 
     "age": 30 
    }, 
    "second": { 
     "name": "Max", 
     "age": 30 
    }, 
    "third": { 
     "name": "Norah", 
     "age": 30 
    }, 
    "fourth": { 
     "name": "Sam", 
     "age": 30 
    } 
} 

Я хочу напечатать ключ верхнего уровня и объект следующим образом:

import json 
import ijson 

fname = "data.json" 

with open(fname) as f: 
    raw_data = f.read() 

data = json.loads(raw_data) 

for k in data.keys(): 
    print k, data[k] 

ВЫХОД:

second {u'age': 30, u'name': u'Max'} 
fourth {u'age': 30, u'name': u'Sam'} 
third {u'age': 30, u'name': u'Norah'} 
first {u'age': 30, u'name': u'James'} 

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

Я хочу использовать добавочную JSON парсер (ijson в данном случае), чтобы достичь того, что я описал ранее:

Приведенный выше код был взят из: No access to top level elements with ijson?

with open(fname) as f: 
    json_obj = ijson.items(f,'').next() # '' loads everything as only one object. 
    for (key, value) in json_obj.items(): 
     print key + " -> " + str(value)  

Это не подходит либо, потому что он также считывает весь файл в памяти. Это не поистине постепенное.

Как я могу выполнить инкрементный синтаксический анализ ключей верхнего уровня и соответствующих объектов из файла JSON в Python?

ответ

0

Поскольку по существу файлы json являются текстовыми файлами, подумайте об удалении верхнего уровня как строки. В принципе, используйте подход read file iterable, где вы объединяете строку с каждой строкой, а затем выходите из цикла, как только строка содержит двойные фигурные скобки }}, сигнализирующие о конце верхнего уровня. Конечно, условие двойной скобки должно разрывать пробелы и разрывы строк.

toplevelstring = '' 

with open('data.json') as f:  
    for line in f: 
     if not '}}' in toplevelstring.replace('\n', '').replace('\s+',''): 
      toplevelstring = toplevelstring + line 
     else: 
      break 

data = json.loads(toplevelstring) 

Теперь, если ваш больше JSON, завернутый в квадратных скобках или других скобках, по-прежнему работать над рутиной, но добавьте строку ниже, чтобы нарезать из первого символа, [, и последних два символа для запятой и разрыва строки после верхнего уровнемера окончательный скобка:

[{ 
    "first": { 
     "name": "James", 
     "age": 30 
    }, 
    "second": { 
     "name": "Max", 
     "age": 30 
    }, 
    "third": { 
     "name": "Norah", 
     "age": 30 
    }, 
    "fourth": { 
     "name": "Sam", 
     "age": 30 
    } 
}, 
{ 
    "data1": { 
     "id": "AAA", 
     "type": 55 
    }, 
    "data2": { 
     "id": "BBB", 
     "type": 1601 
    }, 
    "data3": { 
     "id": "CCC", 
     "type": 817 
    } 
}] 

...

toplevelstring = toplevelstring[1:-2] 
data = json.loads(toplevelstring) 
+0

Входящий файл не может быть отформатирован таким образом. Также идея заключалась в том, чтобы не загружать весь файл в память сразу. – tuxdna

+0

Просьба показать другие форматы. Вы можете добавить условия 'if' для всех возможностей комбинации квадратов/фигурных скобок. Также см. Принятый ответ в ссылке. Итерируемый подход * использует буферизованное управление вводами и памятью, поэтому вам не нужно беспокоиться о больших файлах. * Плюс, цикл прекращается после разбора верхнего уровня, поэтому он не читается в последнюю строку. – Parfait

0

Ответ от github issue [имя файла изменено]

import ijson 
from ijson.common import ObjectBuilder 


def objects(file): 
    key = '-' 
    for prefix, event, value in ijson.parse(file): 
     if prefix == '' and event == 'map_key': # found new object at the root 
      key = value # mark the key value 
      builder = ObjectBuilder() 
     elif prefix.startswith(key): # while at this key, build the object 
      builder.event(event, value) 
      if event == 'end_map': # found the end of an object at the current key, yield 
       yield key, builder.value 


for key, value in objects(open('data.json', 'rb')): 
    print(key, value) 
Смежные вопросы