Làm cách nào để ghi dữ liệu JSON vào một tệp?


1122

Tôi có dữ liệu JSON được lưu trữ trong biến data.

Tôi muốn ghi tệp này vào tệp văn bản để kiểm tra vì vậy tôi không phải lấy dữ liệu từ máy chủ mỗi lần.

Hiện tại, tôi đang thử điều này:

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

Và tôi nhận được lỗi này:

TypeError: phải là chuỗi hoặc bộ đệm, không phải dict

Làm thế nào để khắc phục điều này?

Câu trả lời:


2041

Bạn đã quên phần JSON thực tế - datalà một từ điển và chưa được mã hóa JSON. Viết nó như thế này để tương thích tối đa (Python 2 và 3):

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

Trên một hệ thống hiện đại (ví dụ như hỗ trợ Python 3 và UTF-8), bạn có thể viết một tệp đẹp hơn với

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

8
điều này có thể hữu ích cho việc tuần tự hóa: stackoverflow.com/questions/4512982/ từ
jedierikb

12
Ý bạn là json.dump hay json.dumps?
TerminalDilettante

153
@TerminalDilettante json.dumpghi vào một tệp hoặc đối tượng giống như tệp, trong khi json.dumpstrả về một chuỗi.
phihag

24
btw: để đọc lại dữ liệu sử dụng: với open ('data.txt') là infile: d = json.load (infile). Xem: câu trả lời này
klaas

9
@denvar Không, câu trả lời này được tinh chỉnh. Trên Python 3, json.dumpghi vào tệp văn bản, không phải tệp nhị phân. Bạn sẽ nhận được TypeErrornếu tập tin được mở bằng wb. Trên các phiên bản Python cũ, cả hai wnand wblàm việc. Mã hóa rõ ràng là không cần thiết vì đầu ra của chỉ json.dumpcó ASCII theo mặc định. Nếu bạn có thể chắc chắn rằng mã của bạn không bao giờ chạy trên các phiên bản Python cũ và bạn và người xử lý tệp JSON có thể xử lý chính xác dữ liệu không phải ASCII, bạn có thể chỉ định một và đặt ensure_ascii=False.
phihag

267

Để có được utf8 -encoded tập tin như trái ngược với ascii -encoded trong câu trả lời được chấp nhận cho Python 2 sử dụng:

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

Mã đơn giản hơn trong Python 3:

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

Trên Windows, encoding='utf-8'đối số openvẫn là cần thiết.

Để tránh lưu trữ một bản sao được mã hóa của dữ liệu trong bộ nhớ (kết quả của dumps) và để xuất ra các chuỗi phụ được mã hóa utf8 trong cả Python 2 và 3, hãy sử dụng:

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

Cuộc codecs.getwritergọi không cần thiết trong Python 3 nhưng bắt buộc đối với Python 2


Khả năng đọc và kích thước:

Việc sử dụng ensure_ascii=Falsecho khả năng đọc tốt hơn và kích thước nhỏ hơn:

>>> 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

Cải thiện hơn nữa khả năng đọc bằng cách thêm cờ indent=4, sort_keys=True(như được đề xuất bởi dinos66 ) vào các đối số của dumphoặc dumps. Bằng cách này, bạn sẽ có được cấu trúc được sắp xếp thụt lề độc đáo trong tệp json với chi phí kích thước tệp lớn hơn một chút.


5
Điều unicodenày là không cần thiết - kết quả của json.dumpsđã là một đối tượng unicode. Lưu ý rằng điều này không thành công trong 3.x, trong đó toàn bộ mớ hỗn độn của chế độ tệp đầu ra đã được dọn sạch và json luôn sử dụng các chuỗi ký tự (và ký tự I / O) và không bao giờ byte.
phihag

4
Trong 2.x type(json.dumps('a'))<type 'str'>. Thậm chí type(json.dumps('a', encoding='utf8'))<type 'str'>.
Antony Hatchkins

4
Có, trong 3.x json sử dụng chuỗi, nhưng mã hóa mặc định là ascii. Bạn phải nói rõ ràng rằng bạn muốn utf8ngay cả trong 3.x. Cập nhật câu trả lời.
Antony Hatchkins

4
Ồ, bạn hoàn toàn đúng - Tôi phải nhầm lẫn một cái gì đó. +1 cho chi tiết.
phihag

1
Câu trả lời Python 3.x hoạt động với tôi mặc dù tôi đang sử dụng 2.7. Câu trả lời 2.x trả về lỗi : 'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128). Vì vậy, khi nghi ngờ, sử dụng câu trả lời 3.x!
Blairg23

162

Tôi sẽ trả lời với một chút sửa đổi với các câu trả lời đã nói ở trên và đó là viết một tệp JSON được chỉnh sửa mà mắt người có thể đọc tốt hơn. Đối với điều này, vượt qua sort_keysnhư Trueindentvới 4 ký tự không gian và bạn tốt để đi. Ngoài ra, hãy đảm bảo rằng các mã ascii sẽ không được ghi trong tệp JSON của bạn:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)

2
vẫn nhận đượcUnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
stevek

1
@SirBenBenji Đảm bảo chuỗi bạn đang cố viết để theo dõi: str.decode ('utf-8').
ambodi

1
@SirBenBenji Bạn cũng có thể thử sử dụng codec, vì dinos66 chỉ định bên dưới
Shiv

Bạn cũng phải khai báo mã hóa của mình bằng cách thêm vào # -*- coding: utf-8 -*-sau
shebang

2
+1 cho sort_keys và thụt lề. @aesede Không tốt khi thêm dòng này bởi vì nó sẽ tạo ấn tượng rằng giải pháp này hoạt động với python2 cũng như không ( UnicodeEncodeErrorvới dữ liệu không phải là ascii). Xem giải pháp của tôi để biết chi tiết.
Antony Hatchkins

111

Đọc và viết các tệp JSON bằng Python 2 + 3; hoạt động với 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)

Giải thích về các tham số của json.dump:

  • indent: Sử dụng 4 khoảng trắng để thụt lề mỗi mục, ví dụ: khi một lệnh mới được bắt đầu (nếu không tất cả sẽ nằm trong một dòng),
  • sort_keys: sắp xếp các khóa của từ điển. Điều này hữu ích nếu bạn muốn so sánh các tệp json với một công cụ tìm khác biệt / đặt chúng dưới sự kiểm soát phiên bản.
  • separators: Để ngăn Python thêm các khoảng trắng ở cuối

Với một gói

Hãy xem gói tiện ích của tôi mpucho một siêu đơn giản và dễ nhớ:

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

Đã tạo tệp JSON

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

Kết thúc tập tin phổ biến

.json

Lựa chọn thay thế

Đối với ứng dụng của bạn, những điều sau đây có thể quan trọng:

  • Hỗ trợ bởi các ngôn ngữ lập trình khác
  • Hiệu suất đọc / viết
  • Tính gọn nhẹ (kích thước tệp)

Xem thêm: So sánh các định dạng tuần tự hóa dữ liệu

Trong trường hợp bạn muốn tìm cách tạo tệp cấu hình, bạn có thể muốn đọc các tệp Cấu hình bài viết ngắn của tôi bằng Python


2
Lưu ý rằng force_asciicờ là Truetheo mặc định. Bạn sẽ có các "\u20ac"chuỗi 6 byte không thể đọc được cho mỗi chuỗi trong tệp json của bạn (cũng như bất kỳ ký tự không phải mã ascii nào khác).
Antony Hatchkins

Tại sao bạn sử dụng openđể đọc nhưng io.openđể viết? Có thể sử dụng io.openđể đọc là tốt? Nếu vậy, những thông số nào cần được thông qua?
Micah Zoltu

23

Đối với những người bạn đang cố gắng bỏ tiếng Hy Lạp hoặc các ngôn ngữ "kỳ lạ" khác như tôi nhưng cũng gặp vấn đề (lỗi unicode) với các ký tự lạ như ký hiệu hòa bình (\ u262E) hoặc các ngôn ngữ khác thường có trong dữ liệu được tạo thành json chẳng hạn như Twitter, giải pháp có thể như sau (sort_keys rõ ràng là tùy chọn):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))

1
+1 Trong khi các tài liệu khuyến nghị dựng sẵn python3 openvà được xác io.opennhận codecs.open, thì trong trường hợp này, đây cũng là một bản hack tương thích ngược tốt đẹp. Trong python2 codecs.openlà "ăn tạp" hơn io.open (nó có thể "ăn" cả str và unicode, chuyển đổi nếu cần thiết). Người ta có thể nói rằng việc giải quyết vấn đề này codecs.openbù đắp cho json.dumpsviệc tạo ra các loại đối tượng ( str/ unicode) khác nhau tùy thuộc vào sự hiện diện của các chuỗi unicode trong đầu vào.
Antony Hatchkins

10

Tôi không có đủ danh tiếng để thêm ý kiến, vì vậy tôi chỉ viết một số phát hiện của tôi về TypeError gây phiền nhiễu này ở đây:

Về cơ bản, tôi nghĩ đó chỉ là một lỗi trong json.dump()hàm trong Python 2 - Nó không thể kết xuất dữ liệu Python (từ điển / danh sách) có chứa các ký tự không phải ASCII, ngay cả khi bạn mở tệp có encoding = 'utf-8'tham số. (tức là không có vấn đề gì bạn làm). Nhưng, json.dumps()hoạt động trên cả Python 2 và 3.

Để minh họa điều này, theo dõi câu trả lời của phihag: mã trong câu trả lời của anh ta bị phá vỡ trong Python 2 ngoại lệ TypeError: must be unicode, not str, nếu datacó chứa các ký tự không phải 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)

Tuy nhiên nó hoạt động tốt trong Python 3.


Đưa ra lý do khi bạn tuyên bố một cái gì đó là sai. Sử dụng @nickname để người được thông báo. Bạn không thể viết bình luận, nhưng bạn có thể đọc bình luận. Như đã nêu trong câu trả lời của tôi cho bình luận đầu tiên, hãy thử data = {'asdf': 1}. Bạn sẽ nổi tiếng TypeErrorvới biến thể (thứ hai) của bạn.
Antony Hatchkins

Liên quan ensure_ascii- cần thiết nếu bạn muốn có được đầu ra utf8 "thực". Nếu không có nó, bạn sẽ có ascii đơn giản với 6 byte cho mỗi chữ cái tiếng Nga trái ngược với 2 byte cho mỗi ký tự với cờ này.
Antony Hatchkins

@AntonyHatchkins Bạn đúng cho unicode()một phần. Tôi chỉ nhận ra cho iogói bằng Python 2, write()nhu cầu unicode, không str.
ibic

1
Mã này hoạt động với tôi ngay cả với python2.6.6, Debian (ngày 10 tháng 12 năm 2010). Cũng như với python2.7.9 hoặc python3. Kiểm tra nó một lần nữa, xin vui lòng.
Antony Hatchkins

7

Viết dữ liệu trong tệp bằng JSON sử dụng json.dump () hoặc json.dumps () được sử dụng. viết như thế này để lưu trữ dữ liệu trong tập tin.

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

ví dụ này trong danh sách được lưu trữ vào một tập tin.


nó tương tự nhưng cung cấp với ví dụ
Vishal Gediya

5

Để viết JSON bằng cách thụt lề, "bản in đẹp":

import json

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

Ngoài ra, nếu bạn cần gỡ lỗi JSON được định dạng không đúng và muốn có một thông báo lỗi hữu ích, hãy sử dụng import simplejsonthư viện, thay vì import json(các hàm nên giống nhau)


4
json.dump(data, open('data.txt', 'wb'))

2
Điều này thực hiện tương tự như câu trả lời của @ phihag, nhưng không được đảm bảo hoạt động mọi lúc. Hãy xem xét mã như vậy : f = open('1.txt', 'w'); f.write('a'); input(). Chạy nó và sau đó SYGTERM nó ( Ctrl-Zsau đó kill %1trên linux, Ctrl-Breaktrên Windows). 1.txtsẽ có 0 byte. Đó là bởi vì văn bản đã được đệm và tập tin không bị xóa không đóng vào thời điểm khi xảy ra SYGTERM. withkhối đảm bảo rằng tệp luôn được đóng giống như khối 'thử / cuối cùng' nhưng ngắn hơn.
Antony Hatchkins

3

Viết JSON vào một tệp

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)

Đọc JSON từ tệp

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('')

Chào mừng bạn đến với Stack Overflow. Nếu bạn quyết định trả lời một câu hỏi cũ hơn và có câu trả lời đúng, việc thêm câu trả lời mới vào cuối ngày có thể không giúp bạn nhận được bất kỳ tín dụng nào. Nếu bạn có một số thông tin mới đặc biệt hoặc bạn tin chắc rằng các câu trả lời khác đều sai, bằng mọi cách hãy thêm một câu trả lời mới, nhưng 'một câu trả lời khác' đưa ra thông tin cơ bản tương tự trong một thời gian dài sau khi câu hỏi được hỏi thường thắng ' t kiếm được cho bạn nhiều tín dụng. (Bạn hiển thị một số dữ liệu mẫu; điều đó tốt, nhưng tôi không chắc là đủ, đặc biệt là khi bạn không hiển thị những gì được tạo ra cho dữ liệu mẫu.)
Jonathan Leffler

Ok cảm ơn đã hướng dẫn
iman

2

nếu bạn đang cố gắng viết một dataframe gấu trúc vào một tệp bằng định dạng json, tôi khuyên bạn nên điều này

destination='filepath'
saveFile = open(destination, 'w')
saveFile.write(df.to_json())
saveFile.close()

2

Tất cả các câu trả lời trước đây đều đúng ở đây là một ví dụ rất đơn giản:

#! /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()

nhập mô tả hình ảnh ở đây


1

Câu trả lời được chấp nhận là tốt. Tuy nhiên, tôi gặp phải lỗi "không json serializable" khi sử dụng.

Đây là cách tôi sửa nó với open("file-name.json", 'w')đầu ra:

output.write(str(response))

Mặc dù nó không phải là một sửa chữa tốt vì tệp json mà nó tạo ra sẽ không có dấu ngoặc kép, tuy nhiên thật tuyệt nếu bạn đang tìm kiếm nhanh và bẩn.


0

Dữ liệu JSON có thể được ghi vào một tệp như sau

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]}]

Viết vào một tập tin:

with open('text1.json', 'w') as f:
     json.dump(hist1, f)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.