截断文本文件不会更改文件

时间:2016-01-18 15:15:45

标签: python file python-2.7 python-3.x truncation

当一个新手(比如我)要求在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

2 个答案:

答案 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()