【问题标题】:How do I write JSON data to a file?如何将 JSON 数据写入文件?
【发布时间】:2012-08-31 19:34:40
【问题描述】:

我将 JSON 数据存储在变量 data 中。

我想将其写入文本文件进行测试,这样我就不必每次都从服务器获取数据。

目前,我正在尝试这个:

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

我收到了这个错误:

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

如何解决这个问题?

【问题讨论】:

  • 打开文件时的标志:这里,我们在参数中使用了“w”字母,表示写入,如果库中不存在则创建文件加号表示读取和写入,@ 987654321@

标签: python json


【解决方案1】:

您忘记了实际的 JSON 部分 - data 是一个字典,尚未进行 JSON 编码。写like this 以获得最大的兼容性(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)

【讨论】:

  • 这可能有助于序列化:stackoverflow.com/questions/4512982/…
  • 你的意思是 json.dump 还是 json.dumps?
  • @TerminalDilettante json.dump 写入文件或类似文件的对象,而 json.dumps 返回一个字符串。
  • btw: 重新读取数据使用: with open('data.txt') as infile: d = json.load(infile).见:this answer
  • @denvar 不,这个答案经过微调。在 Python 3 上,json.dump 写入文本文件,而不是二进制文件。如果文件是用wb 打开的,你会得到一个TypeError。在较旧的 Python 版本上,wwb 都可以工作。不需要显式编码,因为默认情况下json.dump 的输出仅为 ASCII。如果您可以确定您的代码永远不会在旧版 Python 版本上运行,并且您和 JSON 文件的处理程序可以正确处理非 ASCII 数据,您可以指定一个并设置ensure_ascii=False
【解决方案2】:

在接受的 Python 2 答案中获取 utf8 编码文件,而不是 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 上,openencoding='utf-8' 参数仍然是必需的。

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

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

通过向dumpdumps 的参数添加标志indent=4, sort_keys=True(由dinos66 建议)进一步提高可读性。这样,您将在 json 文件中获得一个很好的缩进排序结构,但文件大小会稍大一些。

【讨论】:

  • unicode 是多余的 - json.dumps 的结果已经是一个 unicode 对象。请注意,这在 3.x 中失败了,其中所有的输出文件模式已经被清理干净,并且 json 始终使用字符串(和字符 I/O)而不是字节。
  • 在 2.x 中 type(json.dumps('a'))<type 'str'>。甚至type(json.dumps('a', encoding='utf8')) 也是<type 'str'>
  • 是的,在 3.x 中,json 使用字符串,但默认编码是 ascii。即使在 3.x 中,您也必须明确告诉它您想要 utf8。更新了答案。
  • twitter 等数据提供者有时会提供各种编码的数据。上面的代码适用于所有 unicode 推文,但在某些情况下会出现拉丁符号并且您会收到如下错误:'UnicodeEncodeError: 'charmap' codec can't encode character '\xdc' in position 3088: character maps to ' 关于在这些情况下可以做什么的任何想法?
  • Python 3.x 的答案对我有用,即使我使用的是 2.7。 2.x 答案返回错误:'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128)。因此,如有疑问,请使用 3.x 答案!
【解决方案3】:

我会稍微修改一下上述答案,那就是编写一个人眼可以更好地阅读的美化 JSON 文件。为此,将sort_keys 传递为Trueindent,并带有4 个空格字符,您就可以开始了。还要注意确保不会将 ascii 代码写入您的 JSON 文件中:

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

【讨论】:

  • 仍然收到UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
  • @SirBenBenji 确保您尝试写入的字符串遵循:str.decode('utf-8')。
  • @SirBenBenji 你也可以尝试使用编解码器,如下 dinos66 指定的
  • 您还必须通过在 shebang 后添加 # -*- coding: utf-8 -*- 来声明您的编码
  • +1 用于排序键和缩进。 @aesede 添加这一行并不好,因为它会让人觉得这个解决方案也适用于 python2,但它不能(UnicodeEncodeError 使用非 ascii 数据)。详情请见my solution
【解决方案4】:

对于那些试图转储希腊语或其他“外来”语言(例如我)但也遇到奇怪字符(例如和平符号 (\u262E) 或其他经常包含在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))

【讨论】:

  • +1 虽然文档推荐 python3 内置 open 和相关的 io.open 而不是 codecs.open,但在这种情况下,它也是一个很好的向后兼容的 hack。在 python2 中,codecs.open 比 io.open 更“杂食”(它可以“吃”str 和 unicode,必要时进行转换)。可以说,codecs.open 这个怪癖弥补了 json.dumps 根据输入中是否存在 unicode 字符串生成不同类型对象 (str/unicode) 的怪癖。
【解决方案5】:

使用 JSON 将数据写入文件,使用 json.dump()json.dumps()。 像这样写来将数据存储在文件中。

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

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

【讨论】:

  • 类似但提供示例
【解决方案6】:

我没有足够的声誉来添加 cmets,所以我只是在这里写下我对这个烦人的 TypeError 的一些发现:

基本上,我认为这只是 Python 2json.dump() 函数中的一个错误 - 它不能转储包含非 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 中运行良好。

【讨论】:

  • 在您声称某事出错时给出理由。使用@nickname 以便此人得到通知。你不能写 cmets,但你可以读 cmets。正如我对第一条评论的回答中所述,请尝试data = {'asdf': 1}。您将使用您的(第二个)变体获得臭名昭著的 TypeError
  • 关于ensure_ascii - 如果你想得到一个“真正的”utf8 输出,这是必要的。没有它,您将拥有每个俄语字母 6 个字节的普通 ascii,而不是带有此标志的每个字符 2 个字节。
  • @AntonyHatchkins 你是正确的unicode() 部分。我刚刚意识到 Python 2 中的 io 包,write() 需要 unicode,而不是 str
  • 即使使用 python2.6.6,Debian(2010 年 12 月 10 日),此代码也适用于我。以及 python2.7.9 或 python3。请再检查一次。
【解决方案7】:
json.dump(data, open('data.txt', 'wb'))

【讨论】:

  • 这与@phihag 的答案相同,但不能保证始终有效。考虑这样的代码:f = open('1.txt', 'w'); f.write('a'); input()。运行它然后 SYGTERM 它(Ctrl-Z 然后kill %1 在 linux 上,Ctrl-Break 在 Windows 上)。 1.txt 将有 0 个字节。这是因为在 SYGTERM 发生的那一刻,写入被缓冲并且文件既没有刷新也没有关闭。 with 块保证文件总是像 'try/finally' 块一样关闭,但更短。
【解决方案8】:

用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

替代方案

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

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

另见:Comparison of data serialization formats

如果您正在寻找一种制作配置文件的方法,您可能想阅读我的短文Configuration files in Python

【讨论】:

  • 请注意force_ascii 标志默认为True。对于 json 文件中的每个 (以及任何其他非 ascii 字符),您将拥有不可读的 6 字节 "\u20ac" 序列。
  • 为什么阅读时使用open 而写作时使用io.open?是否也可以使用io.open 进行阅读?如果是,应该传递什么参数?
【解决方案9】:

如果您尝试使用 json 格式将 pandas 数据帧写入文件,我建议您这样做

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

【讨论】:

    【解决方案10】:

    之前所有的答案都是正确的,这里是一个非常简单的例子:

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

    【讨论】:

      【解决方案11】:

      接受的答案很好。但是,我使用它遇到了“不是 json 可序列化”错误。

      这是我修复它的方法 以open("file-name.json", 'w') 作为输出:

      output.write(str(response))

      虽然它创建的 json 文件不会有双引号,这不是一个很好的解决方法,但是如果您正在寻找快速和肮脏的东西,那就太好了。

      【讨论】:

        【解决方案12】:

        JSON数据可以按如下方式写入文件

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

        写入文件:

        with open('text1.json', 'w') as f:
             json.dump(hist1, f)
        

        【讨论】:

          【解决方案13】:

          要编写带有缩进的 JSON,“漂亮打印”:

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

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

          【讨论】:

          • open('data.json') 不是以只读模式打开文件吗?
          【解决方案14】:

          将 JSON 写入文件

          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)
          

          从文件中读取 JSON

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

          【讨论】:

          • 欢迎来到 Stack Overflow。如果您决定回答一个已确定且正确答案的旧问题,那么在当天晚些时候添加新答案可能不会让您获得任何荣誉。如果您有一些独特的新信息,或者您确信其他答案都是错误的,请务必添加一个新答案,但是在提出问题很长时间后提供相同基本信息的“另一个答案”通常不会不会为你赢得太多荣誉。 (您展示了一些示例数据;这很好,但我不确定这是否足够,尤其是因为您没有展示为示例数据生成的内容。)
          • 我认为答案还可以,因为它包含更多的细节和清晰度。
          【解决方案15】:

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

          如果字典中有 NumPy 数据类型,json.dumps() 需要一个额外的参数,credit 转到 TypeError: Object of type 'ndarray' is not JSON serializable,它还会修复 TypeError: Object of type int64 is not JSON serializable 等错误:

          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)
          

          【讨论】:

          • 多么迂回的方式来做一些非常简单的事情
          • @user32882 是的,它也让我感到惊讶。像json.dumps这样的标准的弱点。它之所以被否决,可能是因为没有人认为它会那么复杂(包括我在内),它并没有真正回答这个问题,但就我而言,我需要它。
          • 请看一下接受的答案。这不应该超过几行代码。
          • @user32882 据我所知,接受的答案无法导出 numpy 数据类型,这就是我添加此答案的原因。不过,我不确定json.dumpjson.dumps 之间的numpy 数据类型是否存在差异,我现在不能花时间测试这个,我想我还是测试了这个。此答案不应取代已接受的答案,而是添加此特殊情况(一点也不特殊,numpy 数据类型很常见)。
          • @user32882 阅读您的 cmets,您还没有理解这个答案。接受的答案在这里或多或少地重复(dumps 而不是dump 以便您可以使用参数),并且刚刚添加了使 numpy 导出成为可能的类。没有什么反对为正确的缘故投票,但请考虑一下。
          猜你喜欢
          • 1970-01-01
          • 2018-05-26
          • 1970-01-01
          • 2015-08-27
          相关资源
          最近更新 更多