Jak zapisać dane JSON do pliku?

1121

Mam dane JSON przechowywane w zmiennej data.

Chcę to zapisać do pliku tekstowego w celu przetestowania, więc nie muszę za każdym razem pobierać danych z serwera.

Obecnie próbuję tego:

obj = open('data.txt', 'wb')
obj.write(data)
obj.close

I otrzymuję ten błąd:

TypeError: musi być łańcuchem lub buforem, a nie dyktować

Jak to naprawić?

użytkownik1530318
źródło

Odpowiedzi:

2039

Zapomniałeś faktycznej części JSON - datajest słownikiem i nie jest jeszcze zakodowany w JSON. Napisz tak, aby uzyskać maksymalną kompatybilność (Python 2 i 3):

import json
with open('data.json', 'w') as f:
    json.dump(data, f)

W nowoczesnym systemie (tj. Obsługa języka Python 3 i UTF-8) możesz napisać ładniejszy plik

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)
phihag
źródło
8
może to być pomocne w przypadku serializacji: stackoverflow.com/questions/4512982/...
jedierikb
12
Masz na myśli json.dump lub json.dumps?
TerminalDilettante,
153
@TerminalDilettante json.dumpzapisuje do pliku lub obiektu podobnego do pliku, a json.dumpszwraca ciąg znaków.
phihag
24
btw: aby ponownie odczytać dane użyj: z open ('data.txt') jako infile: d = json.load (infile). Zobacz: ta odpowiedź
klaas
9
@denvar Nie, ta odpowiedź jest dokładnie dostrojona. W Pythonie 3 json.dumpzapisuje do pliku tekstowego, a nie pliku binarnego. Dostaniesz, TypeErrorjeśli plik został otwarty za pomocą wb. W starszych wersjach Python oba wnand wbdziałają. Wyraźne kodowanie nie jest konieczne, ponieważ json.dumpdomyślnie wyjściem jest tylko ASCII. Jeśli masz pewność, że Twój kod nigdy nie jest uruchamiany w starszych wersjach języka Python, a Ty i moduł obsługi pliku JSON potrafisz poprawnie obsługiwać dane inne niż ASCII, możesz określić jeden i ustawić ensure_ascii=False.
phihag 19.04.16
267

Aby uzyskać plik zakodowany w utf8 w przeciwieństwie do kodu zakodowanego w ascii w zaakceptowanej odpowiedzi dla Python 2, użyj:

import io, json
with io.open('data.txt', 'w', encoding='utf-8') as f:
  f.write(json.dumps(data, ensure_ascii=False))

Kod jest prostszy w Pythonie 3:

import json
with open('data.txt', 'w') as f:
  json.dump(data, f, ensure_ascii=False)

W systemie Windows encoding='utf-8'argument to openjest nadal konieczny.

Aby uniknąć zapisania zakodowanej kopii danych w pamięci (wynik dumps) i wygenerować bajtowanie zakodowane w utf8 zarówno w Pythonie 2, jak i 3, użyj:

import json, codecs
with open('data.txt', 'wb') as f:
    json.dump(data, codecs.getwriter('utf-8')(f), ensure_ascii=False)

codecs.getwriterRozmowa jest zbędna w Pythonie 3, ale konieczne dla Pythona 2


Czytelność i rozmiar:

Zastosowanie ensure_ascii=Falsedaje lepszą czytelność i mniejszy rozmiar:

>>> json.dumps({'price': '€10'})
'{"price": "\\u20ac10"}'
>>> json.dumps({'price': '€10'}, ensure_ascii=False)
'{"price": "€10"}'

>>> len(json.dumps({'абвгд': 1}))
37
>>> len(json.dumps({'абвгд': 1}, ensure_ascii=False).encode('utf8'))
17

Dalsza poprawa czytelności poprzez dodanie flag indent=4, sort_keys=True(jak sugeruje dinos66 ) do argumentów dumplub dumps. W ten sposób uzyskasz ładnie wciętą posortowaną strukturę w pliku json, kosztem nieco większego rozmiaru pliku.

Antony Hatchkins
źródło
5
unicodeJest zbędny - wynik json.dumpsjest już obiektem Unicode. Zauważ, że kończy się to niepowodzeniem w wersji 3.x, w której cały bałagan trybu plików wyjściowych został oczyszczony, a json zawsze używa ciągów znaków (i znaków we / wy) i nigdy nie bajtów.
phihag
4
W 2.x type(json.dumps('a'))jest <type 'str'>. Nawet type(json.dumps('a', encoding='utf8'))jest <type 'str'>.
Antony Hatchkins
4
Tak, w wersji 3.x json używa ciągów znaków, ale domyślnym kodowaniem jest ascii. Musisz wyraźnie powiedzieć, że chcesz, utf8nawet w wersji 3.x. Zaktualizowałem odpowiedź.
Antony Hatchkins
4
Och, masz całkowitą rację - musiałem coś pomylić. +1 za szczegół.
phihag
1
Odpowiedź na Python 3.x działała dla mnie, mimo że korzystam z wersji 2.7. 2.x odpowiedź zwrócił błąd: 'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128). W razie wątpliwości skorzystaj z odpowiedzi 3.x!
Blairg23,
162

Chciałbym odpowiedzieć z niewielką modyfikacją wyżej wymienionymi odpowiedziami, a mianowicie napisać wstępnie zapisany plik JSON, który ludzkie oczy mogą lepiej odczytać. W tym celu przekazać sort_keysjak Truei indentz 4 znaków spacji i jesteś dobry, aby przejść. Zadbaj również o to, aby kody ascii nie były zapisywane w pliku JSON:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)
ambodi
źródło
2
wciąż się dostajeUnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
stevek
1
@SirBenBenji Upewnij się, że ciąg, który próbujesz zapisać, jest następujący: str.decode ('utf-8').
ambodi
1
@SirBenBenji Możesz także spróbować użyć kodeków, jak określono poniżej w dinos66
Shiv
Musisz także zadeklarować kodowanie, dodając # -*- coding: utf-8 -*-po
shebang
2
+1 za sort_keys i wcięcia. @ aesede Nie warto dodawać tej linii, ponieważ sprawi wrażenie, że to rozwiązanie działa tak samo z python2, jak i nie działa ( UnicodeEncodeErrorz danymi innymi niż ascii). Zobacz szczegóły mojego rozwiązania .
Antony Hatchkins,
111

Odczytywanie i zapisywanie plików JSON za pomocą Python 2 + 3; współpracuje z Unicode

# -*- coding: utf-8 -*-
import json

# Make it work for Python 2+3 and with Unicode
import io
try:
    to_unicode = unicode
except NameError:
    to_unicode = str

# Define data
data = {'a list': [1, 42, 3.141, 1337, 'help', u'€'],
        'a string': 'bla',
        'another dict': {'foo': 'bar',
                         'key': 'value',
                         'the answer': 42}}

# Write JSON file
with io.open('data.json', 'w', encoding='utf8') as outfile:
    str_ = json.dumps(data,
                      indent=4, sort_keys=True,
                      separators=(',', ': '), ensure_ascii=False)
    outfile.write(to_unicode(str_))

# Read JSON file
with open('data.json') as data_file:
    data_loaded = json.load(data_file)

print(data == data_loaded)

Objaśnienie parametrów json.dump:

  • indent: Użyj 4 spacji do wcięcia każdego wpisu, np. Po rozpoczęciu nowego nagrania (w przeciwnym razie wszystkie będą w jednym wierszu),
  • sort_keys: sortuj klucze słowników. Jest to przydatne, jeśli chcesz porównać pliki Json za pomocą narzędzia różnicowego / poddać je kontroli wersji.
  • separators: Aby uniemożliwić Pythonowi dodawanie końcowych białych znaków

Z pakietem

Zajrzyj do mojego pakietu narzędzi, mpuaby uzyskać bardzo prosty i łatwy do zapamiętania:

import mpu.io
data = mpu.io.read('example.json')
mpu.io.write('example.json', data)

Utworzono plik JSON

{
    "a list":[
        1,
        42,
        3.141,
        1337,
        "help",
        "€"
    ],
    "a string":"bla",
    "another dict":{
        "foo":"bar",
        "key":"value",
        "the answer":42
    }
}

Typowe zakończenia plików

.json

Alternatywy

W przypadku aplikacji ważne mogą być:

  • Wsparcie z innych języków programowania
  • Wydajność czytania / pisania
  • Kompaktowość (rozmiar pliku)

Zobacz także: Porównanie formatów serializacji danych

Jeśli szukasz sposobu na utworzenie plików konfiguracyjnych, możesz przeczytać mój krótki artykuł Pliki konfiguracyjne w Pythonie

Martin Thoma
źródło
2
Pamiętaj, że force_asciiflaga jest Truedomyślnie. Będziesz miał nieczytelne "\u20ac"sekwencje 6-bajtowe dla każdej w pliku json (jak również dla każdej innej postaci innej niż ascii).
Antony Hatchkins,
Dlaczego używasz opendo czytania, ale io.opendo pisania? Czy można również używać io.opendo czytania? Jeśli tak, jakie parametry należy przekazać?
Micah Zoltu
23

Dla tych z was, którzy próbują zrzucić greckie lub inne „egzotyczne” języki, takie jak ja, ale mają również problemy (błędy Unicode) z dziwnymi znakami, takimi jak symbol pokoju (\ u262E) lub innymi, które często są zawarte w danych sformatowanych przez JSON takich jak Twitter, rozwiązanie może wyglądać następująco (sort_keys jest oczywiście opcjonalny):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))
dinos66
źródło
1
+1 Podczas docs zaleca python3 polecenie wbudowane openi towarzyszące jej io.opensię codecs.open, w tym przypadku jest to również miły wstecznie kompatybilny Hack. W python2 codecs.openjest bardziej „wszystkożerny” niż io.open (może „jeść” zarówno str, jak i Unicode, konwertując w razie potrzeby). Można powiedzieć, że to codecs.opendziwactwo kompensuje json.dumpsdziwactwo generowania różnych typów obiektów ( str/ unicode) w zależności od obecności ciągów Unicode na wejściu.
Antony Hatchkins
10

Nie mam wystarczającej reputacji, aby dodać w komentarzach, więc po prostu piszę tutaj niektóre z moich odkryć tego irytującego TypeError:

Zasadniczo myślę, że jest to błąd w json.dump()funkcji tylko w Pythonie 2 - Nie może zrzucić danych Pythona (słownika / listy) zawierających znaki spoza ASCII, nawet jeśli otworzysz plik z encoding = 'utf-8'parametrem. (tzn. bez względu na to, co robisz). Ale json.dumps()działa zarówno na Pythonie 2, jak i 3.

Aby to zilustrować, podążając za odpowiedzią phihag: kod w jego odpowiedzi łamie się w Pythonie 2 z wyjątkiem TypeError: must be unicode, not str, jeśli datazawiera znaki spoza ASCII. (Python 2.7.6, Debian):

import json
data = {u'\u0430\u0431\u0432\u0433\u0434': 1} #{u'абвгд': 1}
with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

Działa to jednak dobrze w Pythonie 3.

ibic
źródło
Podaj powody, dla których twierdzisz, że coś jest nie tak. Użyj @nickname, aby osoba została powiadomiona. Nie możesz pisać komentarzy, ale możesz czytać komentarze. Jak już stwierdzono w mojej odpowiedzi na pierwszy komentarz, spróbuj data = {'asdf': 1}. Otrzymasz rozgłos TypeErrorze swoim (drugim) wariantem.
Antony Hatchkins,
Dotyczy ensure_ascii- jest to konieczne, jeśli chcesz uzyskać „prawdziwe” wyjście utf8. Bez niego będziesz miał zwykły ascii z 6 bajtami na rosyjską literę, w przeciwieństwie do 2 bajtów na znak z tą flagą.
Antony Hatchkins,
@AntonyHatchkins Masz rację unicode(). Właśnie uświadomiłem sobie, na ioopakowaniu w Pythonie 2, write()potrzebuje unicode, nie str.
ibic
1
Ten kod działa dla mnie nawet z python2.6.6, Debian (10 grudnia 2010). Jak również z python2.7.9 lub python3. Sprawdź to jeszcze raz, proszę.
Antony Hatchkins
7

Zapisz dane w pliku za pomocą JSON, użyj json.dump () lub json.dumps () . napisz w ten sposób, aby zapisać dane w pliku.

import json
data = [1,2,3,4,5]
with open('no.txt', 'w') as txtfile:
    json.dump(data, txtfile)

ten przykład na liście jest przechowywany w pliku.

Vishal Gediya
źródło
jest podobny, ale daje przykład
Vishal Gediya
5

Aby napisać JSON z wcięciem, „pretty print”:

import json

outfile = open('data.json')
json.dump(data, outfile, indent=4)

Ponadto, jeśli chcesz debugować niepoprawnie sformatowany JSON i potrzebujesz pomocnego komunikatu o błędzie, użyj import simplejsonbiblioteki zamiast import json(funkcje powinny być takie same)

James Wierzba
źródło
4
json.dump(data, open('data.txt', 'wb'))
Alexander
źródło
2
Działa to tak samo jak odpowiedź @ phihag, ale nie gwarantuje się, że będzie działać przez cały czas. Rozważmy taki kod: f = open('1.txt', 'w'); f.write('a'); input(). Uruchom go, a następnie SYGTERM go ( Ctrl-Znastępnie w systemie kill %1Linux, Ctrl-Breakw systemie Windows). 1.txtbędzie miał 0 bajtów. Jest tak, ponieważ zapis został buforowany, a plik nie został opróżniony ani zamknięty w momencie wystąpienia SYGTERM. withblok gwarantuje, że plik jest zawsze zamykany, podobnie jak blok „spróbuj / w końcu”, ale krótszy.
Antony Hatchkins,
3

Zapisywanie JSON do pliku

import json

data = {}
data['people'] = []
data['people'].append({
    'name': 'Scott',
    'website': 'stackabuse.com',
    'from': 'Nebraska'
})
data['people'].append({
    'name': 'Larry',
    'website': 'google.com',
    'from': 'Michigan'
})
data['people'].append({
    'name': 'Tim',
    'website': 'apple.com',
    'from': 'Alabama'
})

with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

Odczytywanie JSON z pliku

import json

with open('data.txt') as json_file:
    data = json.load(json_file)
    for p in data['people']:
        print('Name: ' + p['name'])
        print('Website: ' + p['website'])
        print('From: ' + p['from'])
        print('')
iman
źródło
Witamy w Stack Overflow. Jeśli zdecydujesz się odpowiedzieć na starsze pytanie, które ma dobrze ustalone i poprawne odpowiedzi, dodanie nowej odpowiedzi późno w ciągu dnia może nie przynieść ci uznania. Jeśli masz jakieś nowe, charakterystyczne informacje lub jesteś przekonany, że wszystkie inne odpowiedzi są błędne, dodaj nową odpowiedź, ale „jeszcze jedna odpowiedź”, podając tę ​​samą podstawową informację długo po wygraniu pytania, zwykle wygrywa ” zarobię ci dużo kredytu. (Pokazuje kilka przykładowych danych; to dobrze, ale nie jestem pewien, czy to wystarczy, zwłaszcza, że ​​nie pokazuje się, co jest wytwarzane dla przykładowych danych.)
Jonathan Leffler
Ok dzięki za wskazówki
iman
2

jeśli próbujesz zapisać ramkę danych pandy w pliku w formacie json, poleciłbym to

destination='filepath'
saveFile = open(destination, 'w')
saveFile.write(df.to_json())
saveFile.close()
Franco Miguel Contreras
źródło
2

Wszystkie poprzednie odpowiedzi są poprawne tutaj jest bardzo prosty przykład:

#! /usr/bin/env python
import json

def write_json():
    # create a dictionary  
    student_data = {"students":[]}
    #create a list
    data_holder = student_data["students"]
    # just a counter
    counter = 0
    #loop through if you have multiple items..         
    while counter < 3:
        data_holder.append({'id':counter})
        data_holder.append({'room':counter})
        counter += 1    
    #write the file        
    file_path='/tmp/student_data.json'
    with open(file_path, 'w') as outfile:
        print("writing file to: ",file_path)
        # HERE IS WHERE THE MAGIC HAPPENS 
        json.dump(student_data, outfile)
    outfile.close()     
    print("done")

write_json()

wprowadź opis zdjęcia tutaj

grepit
źródło
1

Przyjęta odpowiedź jest w porządku. Jednak natknąłem się na błąd „nie można serializować json”.

Oto jak to naprawiłem open("file-name.json", 'w')jako wyjście:

output.write(str(response))

Chociaż nie jest to dobra poprawka, ponieważ plik json, który tworzy, nie będzie zawierał podwójnych cudzysłowów, ale jest świetny, jeśli szukasz szybkiego i brudnego.

Akshat Bajaj
źródło
0

Dane JSON można zapisać do pliku w następujący sposób

hist1 = [{'val_loss': [0.5139984398465246],
'val_acc': [0.8002029867684085],
'loss': [0.593220705309384],
'acc': [0.7687131817929321]},
{'val_loss': [0.46456472964199463],
'val_acc': [0.8173602046780344],
'loss': [0.4932038113037539],
'acc': [0.8063946213802453]}]

Napisz do pliku:

with open('text1.json', 'w') as f:
     json.dump(hist1, f)
Ashok Kumar Jayaraman
źródło