当一个新手(比如我)要求在python中阅读/处理文本文件时,他经常得到如下答案:
with open("input.txt", 'r') as f:
for line in f:
#do your stuff
现在我想在特殊行之后截断我正在阅读的文件中的所有内容。修改上面的例子后我使用:
with open("input.txt", 'r+') as file:
for line in file:
print line.rstrip("\n\r") #for debug
if line.rstrip("\n\r")=="CC":
print "truncating!" #for debug
file.truncate();
break;
并期望它在看到第一个“CC”之后扔掉所有东西。在input.txt上运行此代码:
AA
CC
DD
在控制台上打印以下内容(如预期的那样):
AA
CC
truncating!
但文件“input.txt”保持不变!?!?
怎么会这样?我做错了什么?
编辑:操作完成后,我希望文件包含:
AA
CC
答案 0 :(得分:5)
看起来你已经成为Python内部使用的预读缓冲区的牺牲品。来自documentation for the file.next() method:
文件对象是它自己的迭代器,例如
iter(f)
返回f(除非f关闭)。当文件用作迭代器时,通常在for
循环中(例如,for line in f: print line.strip()
),重复调用next()
方法。此方法返回下一个输入行,或者当文件打开以供读取时触发EOF时引发StopIteration
(当文件打开以进行写入时,行为未定义)。为了使for
循环成为循环文件行的最有效方式(一种非常常见的操作),next()
方法使用隐藏的预读缓冲区。使用预读缓冲区的结果是,将next()
与其他文件方法(如readline()
)组合不起作用。但是,使用seek()
将文件重新定位到绝对位置将刷新预读缓冲区。
结果是文件的位置不是你在截断时所期望的位置。解决这个问题的一种方法是使用readline
循环遍历文件,而不是迭代器:
line = file.readline()
while line:
...
line = file.readline()
答案 1 :(得分:3)
除了glibdud的答案之外,truncate()还需要删除内容的大小。您可以通过tell()
命令获取文件中的当前位置。正如他所提到的,通过使用for循环,next()
禁止像tell这样的命令。但是在建议的while循环中,你可以截断当前的tell() - 位置。所以完整的代码看起来像这样:
Python 3:
with open("test.txt", 'r+') as file:
line = file.readline()
while line:
print(line.strip())
if line.strip() == "CC":
print("truncating")
file.truncate(file.tell())
break
line = file.readline()