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

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

这会导致错误:

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


当前回答

对于那些试图转储希腊语或其他“外来”语言(如我),但同时也遇到诸如和平符号(\u262E)等奇怪字符或其他通常包含在json格式数据(如Twitter)中的字符的问题(unicode错误)的人,解决方案可能如下(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))

其他回答

data是Python字典。在编写之前,需要将其编码为JSON。

使用此选项可获得最大兼容性(Python 2和3):

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

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

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

请参阅json文档。

对于喜欢oneliner的人(因此,with语句不是一个选项),一个比留下悬空打开的文件描述符更干净的方法是使用pathlib中的write_text并执行以下操作:

pathlib.Path("data.txt").write_text(json.dumps(data))

在某些情况下,这在不允许语句的上下文中很有用,例如:

[pathlib.Path(f"data_{x}.json").write_text(json.dumps(x)) for x in [1, 2, 3]]

我并不是说它应该优先于使用(而且可能会慢一些),只是另一种选择。

要获得utf8编码文件,而不是Python 2公认答案中的ascii编码文件,请使用:

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上,仍然需要使用encoding='utf-8'参数打开。

要避免在内存中存储数据的编码副本(转储的结果),并在Python 2和3中输出utf8编码字节字符串,请使用:

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

通过在dump或dumps的参数中添加标志indent=4,sort_keys=True(如dinos66所建议的),进一步提高可读性。通过这种方式,您将在json文件中获得一个很好的缩进排序结构,代价是文件大小稍大。

这只是对json.dumps用法的一个额外提示(这不是问题的答案,而是那些必须转储numpy数据类型的人的一个技巧):

如果字典中有NumPy数据类型,json.dumps()需要一个额外的参数,信用转到TypeError:'ndarray'类型的对象不可json序列化,它还将修复TypeError:int64类型的对象不能json序列化等错误:

class NumpyEncoder(json.JSONEncoder):
    """ Special json encoder for np types """
    def default(self, obj):
        if isinstance(obj, (np.int_, np.intc, np.intp, np.int8,
                            np.int16, np.int32, np.int64, np.uint8,
                            np.uint16, np.uint32, np.uint64)):
            return int(obj)
        elif isinstance(obj, (np.float_, np.float16, np.float32,
                              np.float64)):
            return float(obj)
        elif isinstance(obj, (np.ndarray,)):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

然后运行:

import json

#print(json.dumps(my_data[:2], indent=4, cls=NumpyEncoder)))
with open(my_dir+'/my_filename.json', 'w') as f:
    json.dumps(my_data, indent=4, cls=NumpyEncoder)))

在np.array()的情况下,您可能还希望返回字符串而不是列表,因为数组被打印为分布在行上的列表,如果您有大或多个数组,则会放大输出。需要注意的是:稍后从转储的字典中访问项以将其恢复为原始数组会更加困难。然而,如果您不介意只使用一个数组字符串,这会使字典更可读。然后交换:

        elif isinstance(obj, (np.ndarray,)):
            return obj.tolist()

具有:

        elif isinstance(obj, (np.ndarray,)):
            return str(obj)

或者只是:

        else:
            return str(obj)

在将字典作为json写入文件之前,必须使用json库将该字典转换为json字符串。

import json

data = {
    "field1":{
        "a": 10,
        "b": 20,
    },
    "field2":{
        "c": 30,
        "d": 40,
    },
}

json_data = json.dumps(json_data)

此外,您还可以向json数据添加缩进以使其看起来更漂亮。

json_data = json.dumps(json_data, indent=4)

如果要在转换为json之前对密钥进行排序,

json_data = json.dumps(json_data, sort_keys=True)

您也可以使用这两者的组合。

有关更多功能,请参阅此处的json文档

最后,您可以写入一个json文件

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