如何将JSON数据写入文件?

1725

我如何将存储在字典 data 中的JSON数据写入文件中?

f = open('data.json', 'wb')
f.write(data)

这会导致错误:

TypeError: 必须是字符串或缓冲区,而不是字典


关于打开文件时的标志:这里我们在参数中使用了"w"字母,表示写入并将在库中创建文件(如果不存在)。加号表示读取和写入。https://www.guru99.com/reading-and-writing-files-in-python.html#1 - Charlie Parker
2
使用 pathlib 一行代码实现:Path("data.json").write_text(json.dumps(data)) - phoenix
16个回答

3078

data 是一个Python字典。在写入之前需要将其编码为JSON格式。

为了最大程度的兼容性(Python 2和3)使用以下方式:

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

在现代系统上(即Python3和UTF-8支持),您可以使用以下方式编写一个更好的文件:

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

请参阅json文档。


250
json.dump用于将数据写入文件或类似文件的对象,而json.dumps则返回一个字符串。 - phihag
json dump会将json以字符串的形式写入文件中。我如何获得一个不是以字符串形式,而只是类似字典的json文件呢?这是否可能? - curiouscheese
@curiouscheese 听起来是一个在StackOverflow上问的好问题!确保解释清楚你所说的“类似字典”的意思 - 也许你可以提供一个示例文件?最终,文件只是一系列字节。 - phihag
我已经找到了解决方案。我希望在JSON文件中的格式是[{"name":"Jack", "age":34}, {"name":"Joe", "age":54}],而不是"[{"name":"Jack", "age":34}, , {"name":"Joe", "age":54}]"。我只是使用上下文管理器和f.write(json_string)而不是json.dumps(json_string),它能正常工作。因为我生成的JSON字符串来自dataframe.to_json() - curiouscheese

328

为了获取使用utf8编码而不是ascii编码的文件,在Python 2中使用以下代码:

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

Python 3 的代码更简单:

import json
with open('data.txt', 'w') as f:
  json.dump(data, f, ensure_ascii=False)
在Windows平台上,使用open函数时需要添加encoding='utf-8'参数。为了避免在内存中保存数据的编码副本(即dumps函数的结果),并且在Python 2和3中输出UTF-8编码的字节串,请使用以下代码:
import json, codecs
with open('data.txt', 'wb') as f:
    json.dump(data, codecs.getwriter('utf-8')(f), ensure_ascii=False)

codecs.getwriter 调用在 Python 3 中是多余的,但在 Python 2 中是必需的。


可读性和大小:

使用 ensure_ascii=False 可以提高可读性并减小文件大小:

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

按照dinos66的建议,在dumpdumps的参数中添加标志indent=4, sort_keys=True,可以进一步提高可读性。这样,您将获得一个漂亮缩进且排序的结构,代价是文件大小稍微增大。


5
unicode 是多余的 - json.dumps 的结果已经是一个 unicode 对象。请注意,在 Python 3.x 版本中,输出文件模式的混乱已经得到了清理,json 始终使用字符串(和字符 I/O),而不是字节。 - phihag

193

我会稍微修改之前的答案,并建议编写一个格式优美的 JSON 文件,以便人类更好地阅读。为此,请将sort_keys设置为True,将indent设置为 4 个空格字符,您就可以开始了。还要注意确保在您的 JSON 文件中不会写入 ASCII 码:

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

131

使用Python 2+3读写JSON文件;支持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)

json.dump 参数的解释:

  • indent: 用 4 个空格对每个条目进行缩进,例如当开始一个新字典时(否则所有内容都在一行),
  • sort_keys: 对字典的键进行排序。如果您想使用差异工具比较 json 文件 / 将其纳入版本控制中,这将非常有用。
  • separators: 防止 Python 添加尾随空格

使用软件包

请查看我的实用程序包mpu,其中包含一个超级简单且易于记忆的方法:

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

创建的 JSON 文件

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

常见的文件扩展名

.json

备选方案

对于您的应用程序,以下可能很重要:

  • 其他编程语言的支持
  • 读取/写入性能
  • 紧凑性(文件大小)

另请参阅:数据序列化格式比较

如果您更倾向于寻找一种制作配置文件的方法,您可能想阅读我的简短文章Python 中的配置文件


26

对于那些试图放弃希腊语或其他“异国”语言的人,例如我自己,但是也遇到与奇怪字符(如和平符号(\u262E))有关的问题,这些字符经常出现在json格式数据中,例如Twitter的数据,解决方法如下(sort_keys显然是可选的):

对于那些试图摆脱像我一样的希腊语或者其他"异国"语言,但同时又遇到由奇怪字符(例如和平符号\u262E等)引起的Unicode错误,这些字符经常出现在json格式的数据中,比如Twitter的数据。解决方法如下(sort_keys 明显是可选的):

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

13

由于声望不够高,我无法在评论中添加内容,因此我在这里写下了一些我发现的令人恼火的TypeError错误:

基本上,我认为这是Python 2中json.dump()函数的一个bug——它不能转储包含非ASCII字符(字典/列表)数据的Python数据,即使您使用encoding='utf-8'参数打开文件。 (即无论您做什么)。但是,json.dumps()适用于Python 2和3。

为了说明这一点,接着phihag的答案:如果data包含非ASCII字符,则他的答案中的代码在Python 2中会出现异常TypeError: must be unicode, not str。(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)

然而在 Python 3 中它可以正常工作。


@AntonyHatchkins 你关于 unicode() 部分是正确的。我刚刚意识到在 Python 2 中的 io 包中,write() 需要使用 unicode 而不是 str - ibic
1
这段代码在我的Python 2.6.6上和Debian (Dec 10 2010)上运行良好,也适用于Python 2.7.9或Python 3。请再次检查一下。 - Antony Hatchkins

11

使用JSON将数据写入文件,可以使用json.dump()json.dumps()方法。按照以下方式编写代码以将数据存储在文件中。

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

这个例子中的列表被存储到一个文件中。


它类似但提供示例 - Vishal Gediya

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

3
这个方法与@phihag的答案相同,但并不保证始终有效。考虑以下代码:f = open('1.txt', 'w'); f.write('a'); input()。运行它,然后SYGTERM它(在Linux上按Ctrl-Z然后kill %1,在Windows上按Ctrl-Break)。1.txt将有0字节。这是因为写入是缓冲的,文件在SYGTERM发生时既没有被刷新也没有被关闭。 with块保证该文件始终会被关闭,就像“try/finally”块一样,但更短。 - Antony Hatchkins
1
如果你喜欢使用一行代码,更简洁的选项可能是使用pathlib,并执行类似于'pathlib.Path("data.txt").write_text(json.dumps(data))'这样的操作。 - kriss

6
要以缩进的方式编写JSON,即“漂亮打印”:
import json

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

另外,如果您需要调试格式不正确的JSON,并且希望获得有用的错误消息,请使用import simplejson库,而不是import json(函数应该相同)


open('data.json') 不是以只读模式打开文件吗? - Mihai Todor

5
所有之前的答案都是正确的,这里有一个非常简单的例子:
#! /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()

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接