【问题标题】:How to append data to a json file?如何将数据附加到json文件?
【发布时间】:2012-10-11 06:14:22
【问题描述】:

我正在尝试创建一个将条目添加到 json 文件的函数。最终,我想要一个看起来像

的文件
[{"name" = "name1", "url" = "url1"}, {"name" = "name2", "url" = "url2"}]

等等。这就是我所拥有的:

def add(args):
    with open(DATA_FILENAME, mode='r', encoding='utf-8') as feedsjson:
        feeds = json.load(feedsjson)
    with open(DATA_FILENAME, mode='w', encoding='utf-8') as feedsjson:
        entry = {}
        entry['name'] = args.name
        entry['url'] = args.url
        json.dump(entry, feedsjson)

这确实会创建一个条目,例如 {"name"="some name", "url"="some url"}。但是,如果我再次使用这个 add 函数,使用不同的名称和 url,第一个会被覆盖。我需要做什么才能将第二个(第三个...)条目附加到第一个条目上?

编辑:这个问题的第一个答案和 cmets 指出了一个明显的事实,即我没有在写入块中使用 feeds。不过,我不知道该怎么做。例如,以下显然不会这样做:

with open(DATA_FILENAME, mode='a+', encoding='utf-8') as feedsjson:
    feeds = json.load(feedsjson)
    entry = {}
    entry['name'] = args.name
    entry['url'] = args.url
    json.dump(entry, feeds)

【问题讨论】:

  • 你甚至没有在第二个块中使用feeds,所以你当然会丢失之前的输出。
  • 哦,伙计。当然。我显然太累了:(
  • enter link description here 也许你可以看看这个问题。在列表中添加新数据更容易,而且不会破坏 JSON 格式。

标签: python json


【解决方案1】:
import jsonlines

object1 = {
               "name": "name1",
               "url": "url1"
          }

object2 = {
               "name": "name2",
               "url": "url2"
          }   


# filename.jsonl is the name of the file
with jsonlines.open("filename.jsonl", "a") as writer:   # for writing
    writer.write(object1)
    writer.write(object2)

with jsonlines.open('filename.jsonl') as reader:      # for reading
    for obj in reader:
        print(obj)             

访问https://jsonlines.readthedocs.io/en/latest/了解更多信息

【讨论】:

    【解决方案2】:

    您可以简单地从源文件中导入数据,读取它,然后将要附加的内容保存到变量中。然后打开目标文件,将里面的列表数据分配给一个新变量(大概这都是有效的 JSON),然后在这个列表变量上使用“附加”函数并将第一个变量附加到它。 Viola,您已附加到 JSON 列表。现在只需用新添加的列表(作为 JSON)覆盖您的目标文件。

    'open' 函数中的 'a' 模式在这里不起作用,因为它只会将所有内容附加到文件的末尾,这将使其成为无效的 JSON 格式。

    【讨论】:

      【解决方案3】:

      这个,为我工作:

      with open('file.json', 'a') as outfile:
          outfile.write(json.dumps(data))
          outfile.write(",")
          outfile.close()
      

      【讨论】:

        【解决方案4】:

        一种可能的解决方案是手动进行连接,这里有一些有用的 代码:

        import json
        def append_to_json(_dict,path): 
            with open(path, 'ab+') as f:
                f.seek(0,2)                                #Go to the end of file    
                if f.tell() == 0 :                         #Check if file is empty
                    f.write(json.dumps([_dict]).encode())  #If empty, write an array
                else :
                    f.seek(-1,2)           
                    f.truncate()                           #Remove the last character, open the array
                    f.write(' , '.encode())                #Write the separator
                    f.write(json.dumps(_dict).encode())    #Dump the dictionary
                    f.write(']'.encode())                  #Close the array
        

        在脚本之外编辑文件时应该小心,不要在末尾添加任何间距。

        【讨论】:

        • 遗憾的是,如果不是二进制模式,它在 Python 3.2+ 中将不再工作,因为您需要告知编码。以下 stackoverflow 问题给出了一些提示:stackoverflow.com/questions/18857352/…
        • 这个代码可能是作者要找的,但是它有问题。对于空文件,它添加双引号,附加它而不是删除它们,因此它看起来是嵌套的,逗号有额外的空间,json 在默认转储行为中没有,字符串也是额外编码的,可能只是开头的字节字符串.所以我编辑代码以按预期工作。
        【解决方案5】:

        如果文件存在,则将条目附加到文件内容中,否则将条目附加到空列表并写入文件中:

        a = []
        if not os.path.isfile(fname):
            a.append(entry)
            with open(fname, mode='w') as f:
                f.write(json.dumps(a, indent=2))
        else:
            with open(fname) as feedsjson:
                feeds = json.load(feedsjson)
        
            feeds.append(entry)
            with open(fname, mode='w') as f:
                f.write(json.dumps(feeds, indent=2))
        

        【讨论】:

        • feeds 是一本字典。尝试您的代码时出现以下错误: AttributeError: 'dict' object has no attribute 'append' 但是,如果我用更新更改附加,它可以工作
        • 另外,这也可能导致重复条目。
        【解决方案6】:

        我有一些类似的代码,但不会每次都重写整个内容。这意味着定期运行并在数组末尾附加一个 JSON 条目。

        如果文件还不存在,它会创建它并将 JSON 转储到一个数组中。如果文件已经被创建,它会走到最后,用, 替换] 将新的JSON 对象放入,然后用另一个] 再次关闭它

        # Append JSON object to output file JSON array
        fname = "somefile.txt"
        if os.path.isfile(fname):
            # File exists
            with open(fname, 'a+') as outfile:
                outfile.seek(-1, os.SEEK_END)
                outfile.truncate()
                outfile.write(',')
                json.dump(data_dict, outfile)
                outfile.write(']')
        else: 
            # Create file
            with open(fname, 'w') as outfile:
                array = []
                array.append(data_dict)
                json.dump(array, outfile)
        

        【讨论】:

          【解决方案7】:

          使用a 而不是w 应该可以让您更新文件,而不是创建新文件/覆盖现有文件中的所有内容。

          请参阅this answer 了解模式的差异。

          【讨论】:

          • 漂亮!只需要'a'而不是'w'。没什么疯狂的
          • 这对我不起作用。它只是连接两个不同的列表,使 json 无效。它看起来像这样:[data1, data2, ..., dataN][dataN+1, dataN+2, ...]
          • 这只是附加到 文件,而不是文件内的数组。
          • 假设您的写入和读取是周期性的,您可以使用此方法,然后在单独的线程或进程中使用一个小函数将文件展平回 JSON 可读格式。不如纯附加快,但它至少应该让你的写入速度更快。
          【解决方案8】:

          您可能希望使用 JSON list 而不是字典作为顶级元素。

          所以,用一个空列表初始化文件:

          with open(DATA_FILENAME, mode='w', encoding='utf-8') as f:
              json.dump([], f)
          

          然后,您可以在此列表中追加新条目:

          with open(DATA_FILENAME, mode='w', encoding='utf-8') as feedsjson:
              entry = {'name': args.name, 'url': args.url}
              feeds.append(entry)
              json.dump(feeds, feedsjson)
          

          请注意,这执行起来会很慢,因为每次调用add 时都会重写文件的全部内容。如果你在循环中调用它,可以考虑提前将所有提要添加到一个列表中,然后一次性写出该列表。

          【讨论】:

          • 谢谢。 feeds 未在您的代码示例中定义。它应该是原始文件的 json.dump 吗?这就是我一直在尝试的方法,但它似乎不起作用。
          • 对不起。它旨在仅替换原始 add 中的写入块。
          • 当你用with open(DATA_FILENAME, mode='r', encoding='utf-8') as f: json.dump([], f)初始化文件时,你会想用with open(DATA_FILENAME, mode='w', encoding='utf-8') as f: json.dump([], f)来打开文件进行写入而不是读取(如果文件不存在,它可以'不被阅读)。
          • 糟糕,已修复。谢谢。
          • @Manakin:是的。如果您经常追加,您可能希望使用不同的格式(请参阅接受的答案),或将每个 JSON 对象放在单独的行上(并每行读取一个对象 - 而不是将整个文件作为单个对象)。跨度>
          【解决方案9】:

          json 可能不是磁盘格式的最佳选择;它在附加数据方面遇到的麻烦就是一个很好的例子,说明了为什么会这样。具体来说,json 对象的语法意味着必须读取和解析整个对象才能理解它的任何部分。

          幸运的是,还有很多其他选择。一个特别简单的就是 CSV; python的标准库很好地支持它。最大的缺点是它只适用于文本;如果需要,它需要程序员采取额外的行动将值转换为数字或其他格式。

          另一个没有此限制的选项是使用 sqlite 数据库,该数据库在 python 中也具有内置支持。这可能与您已经拥有的代码有更大的不同,但它更自然地支持您显然正在尝试构建的“稍微修改”模型。

          【讨论】:

          • 谢谢。我正在尝试编写一个小播客聚合器。对于可能有 8 到 10 行的提要数据,sqlite 数据库是不是有点矫枉过正?
          • 如果您的数据是统一的,您可以附加到类似 json 的文件中,只需让每一行都包含您想要的对象。然后当你阅读时,只需将每一行解析为一个 json 对象即可。
          • @Jonno_FTW:使用这种格式的文件会比 sqlite 更麻烦;在前一种情况下,您需要将所有对象累积到一个有用的结构中。虽然这只有六行 python,但仍然比处理 sqlite 或 CSV 所需的 1 行多六行。
          • @SingleNegationElimination 这假设您的数据是统一的并且很好地适合 SQL 表。加上 json,您可以获得比 CSV 的字符串更多的类型。另外,您可以使用[json.loads(i) for i in open('somefile.json','r').readlines()] 加载整个内容
          • 它对我来说是工作,你可以使用jsonlines 包来读写json文件
          【解决方案10】:

          您从来没有写过与您读入的数据有关的任何内容。您想将提要中的数据结构添加到您正在创建的新数据结构中吗?

          或者您可能想以附加模式打开文件open(filename, 'a'),然后添加您的字符串,方法是写入由json.dumps 生成的字符串,而不是使用json.dump - 但 nneonneo 指出这将是无效的 json。

          【讨论】:

          • 这是一个很好的尝试,但它会将无效的 JSON 写入文件(例如 {"a":"b"}{"c":"d"})。
          • 是的,我的意思是将提要中的数据结构添加到我正在创建的数据结构中。让我编辑问题以明确说明。
          猜你喜欢
          • 2018-11-17
          • 2011-12-15
          • 2019-05-11
          • 2016-04-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多