如何使用Python更新JSON文件

112
我试图更新现有的 Json 文件,但是由于某种原因,所请求的值未被更改,而是将整个新值集合(包括新值)追加到原始文件中。
jsonFile = open("replayScript.json", "r+")
data = json.load(jsonFile)


tmp = data["location"]
data["location"] = "NewPath"

jsonFile.write(json.dumps(data))

结果是:

需要:

{
   "location": "NewPath",
   "Id": "0",
   "resultDir": "",
   "resultFile": "",
   "mode": "replay",
   "className":  "",
   "method":  "METHOD"
}

实际:

{
"location": "/home/karim/storm/project/storm/devqa/default.xml",
"Id": "0",
"resultDir": "",
"resultFile": "",
"mode": "replay",
"className":  "",
"method":  "METHOD"
}
{
    "resultDir": "",
    "location": "pathaaaaaaaaaaaaaaaaaaaaaaaaa",
    "method": "METHOD",
    "className": "",
    "mode": "replay",
    "Id": "0",
    "resultFile": ""
}
4个回答

201

问题在于您已经打开了一个文件并读取了其内容,因此光标位于文件末尾。通过使用相同的文件句柄来写入,您实际上是在向文件追加内容。

最简单的解决方法是在读取文件后关闭文件,然后重新打开它以进行写入操作。

with open("replayScript.json", "r") as jsonFile:
    data = json.load(jsonFile)

data["location"] = "NewPath"

with open("replayScript.json", "w") as jsonFile:
    json.dump(data, jsonFile)

或者,你可以使用 seek() 来将光标移动回文件开头,然后开始写入,接着使用 truncate() 来处理新数据比以前数据小的情况。

with open("replayScript.json", "r+") as jsonFile:
    data = json.load(jsonFile)

    data["location"] = "NewPath"

    jsonFile.seek(0)  # rewind
    json.dump(data, jsonFile)
    jsonFile.truncate()

19
感谢您解释了 seek()truncate() 的用法。然而,我认为将 jsonFile.write(json.dumps(data)) 更改为 jsonFile.dump(data, f) 会更加符合 Python 的风格。 - BoltzmannBrain
2
如果我想更新多个位置如data["location_2"] = "NewPath_2",那么我是否应该将 jsonFile.seek(0); dump(); truncate() 应用于该行,还是只需要在所有更新的末尾进行一次 jsonFile.seek(0) ; json.dump(data, jsonFile); jsonFile.truncate() - alper
2
json.dump(data, jsonFile); jsonFile.truncate() 只更新文件中的更新部分还是重新写入整个文件?@Shawn Chin - alper
在第二个例子中,tmp = data["location"] 看起来是多余的,应该被删除。此外,我使用了 json.dump(data, jsonFile, indent=4) 来触发漂亮打印,这样 JSON 文件的布局就不会是紧凑型。 - Sun Bear
我在使用json.load()函数时遇到了问题。经过一段时间的研究,我发现它失败是因为JSON文件中有一些注释。一旦我将它们删除,它就完美地工作了。希望能对某人有所帮助。 - BourbonCreams
显示剩余2条评论

54
def updateJsonFile():
    jsonFile = open("replayScript.json", "r") # Open the JSON file for reading
    data = json.load(jsonFile) # Read the JSON into the buffer
    jsonFile.close() # Close the JSON file

    ## Working with buffered content
    tmp = data["location"] 
    data["location"] = path
    data["mode"] = "replay"

    ## Save our changes to JSON file
    jsonFile = open("replayScript.json", "w+")
    jsonFile.write(json.dumps(data))
    jsonFile.close()

9
好的,我会尽力为您进行翻译。"我很好奇,为什么需要使用 tmp 变量?将其传递给 tmp = data['location'] 和直接使用 data['location'] 路径有什么区别吗?" - SMDC
3
我猜这只是一个例子,展示了“使用缓冲内容”的工作方式,就像评论所说的那样。 - Christoph Lösch

-1
def updateJsonFile():   
    with open(os.path.join(src, "replayScript.json"), "r+") as jsonFile:
        data = json.load(jsonFile)
        jsonFile.truncate(0)
        jsonFile.seek(0)
        data["src"] = "NewPath"
        json.dump(data, jsonFile, indent=4)
        jsonFile.close()

2
请添加一个简要的解释,说明它如何/为什么解决了问题。 - rachwa

-1
def writeConfig(key, value):
        with open('config.json') as f:
            data = json.load(f)
            # Check if key is in file
            if key in data:
                # Delete Key
                del data[key]
                cacheDict = dict(data)
                # Update Cached Dict
                cacheDict.update({key:value})
                with open(dir_path + 'config.json', 'w') as f:
                    # Dump cached dict to json file
                    json.dump(cacheDict, f, indent=4)

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