就地修改文本文件(读写文本文件)

modify text file in place (read and write text file)

当我尝试修改我的一个文本文件时,我在 python 中遇到了 file.readlines()file.writelines() 的奇怪行为。你能帮我理解这种意想不到的行为吗?真是让我很困惑。

这是一个简单的例子,可以用来重现奇怪的行为: 我知道我可以通过阅读文本内容、更改文本以及使用下面的 方法 1 等 2 个上下文管理器写入文本来修改文本,它工作得很好并且非常健壮(我总是得到我所期望的):

方法一

with open("sample.txt","r")as file:
    content = file.readlines()
    content[0] = "a = 1\n"
    content[2] = "v = 3\n"
    content[3] = "v\n"

with open("sample.txt","w")as file:
    file.writelines(content)

sample.txt:

a = -1

v = -3
vv

abc

c=1

输出文件:

a = 1

v = 3
v

abc

c=1

不过,我尽量省力打字,遵循“DRY”原则。我改用了以下代码(我相信我在堆栈溢出的某个地方看到了它)。这真的让我很惊讶,也让我很痛苦地找到了这个问题。它有时工作得很好,有时它不依赖于文本文件。

方法二

with open("sample.txt","r+")as file:
    content = file.readlines()
    content[0] = "a = 1\n"
    content[2] = "v = 3\n"
    content[3] = "v\n"
    file.seek(0)
    file.writelines(content)

使用相同的输入文本文件,它输出以下文本文件:

a = 1

v = 3
v

abc

c=1
=1

我非常好奇方法2输出的文本文件中的最后一行=1,除了那一行,其他似乎都是正确的。你能解释一下那条线的产生吗?

更新

我们仍然可以使用单个上下文管理器就地修改文本文件,但是为了避免现有文件的残留,我们需要查找文件的开头并将其完全截断。

with open("sample.txt","r+")as file:
    content = file.readlines()
    content[0] = "a = 1\n"
    content[2] = "v = 3\n"
    content[3] = "v\n"
    file.seek(0)
    file.truncate(0)
    file.writelines(content)

当您以 r+ 模式打开文件并返回开头时,您将覆盖从该位置开始的字节,但该位置 之后 的字节将不会被替换。

您看到的 =1 是旧内容的残余,在您用比以前包含的字符串更短的字符串替换文件的开头之后。