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

ead*_*ead 4 python file truncation python-2.7 python-3.x

当一个新手(像我一样)要求在python中读取/处理文本文件时,他经常得到如下答案:

with open("input.txt", 'r') as f:
    for line in f:
        #do your stuff
Run Code Online (Sandbox Code Playgroud)

现在我想在特殊行之后截断我正在阅读的文件中的所有内容.修改上面的例子后,我使用:

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;
Run Code Online (Sandbox Code Playgroud)

并期望它在看到第一个"CC"之后扔掉所有东西.在input.txt上运行此代码:

AA
CC
DD
Run Code Online (Sandbox Code Playgroud)

控制台上打印以下内容(如预期):

AA
CC
truncating!
Run Code Online (Sandbox Code Playgroud)

但文件"input.txt"保持不变!?!?

怎么可能?我做错了什么?

编辑:操作后我希望文件包含:

AA
CC
Run Code Online (Sandbox Code Playgroud)

gli*_*dud 5

看起来你正在成为Python内部使用的预读缓冲区的牺牲品.从file.next()方法文档:

文件对象是它自己的迭代器,例如iter(f)返回f(除非f被关闭).当文件用作迭代器时,通常在for循环中(例如,for line in f: print line.strip()),next()重复调用该方法.此方法返回下一个输入行,或者StopIteration当文件打开以供读取时触发EOF时引发(当文件打开以进行写入时行为未定义).为了使for循环成为循环文件行的最有效方式(一种非常常见的操作),该next()方法使用隐藏的预读缓冲区.由于使用预读缓冲区,next()与其他文件方法(如readline())结合使用是行不通的.但是,使用seek()将文件重新定位到绝对位置将刷新预读缓冲区.

结果是文件的位置不是你在截断时所期望的位置.解决这个问题的一种方法是使用readline循环文件而不是迭代器:

line = file.readline()
while line:
    ...
    line = file.readline()
Run Code Online (Sandbox Code Playgroud)


Abu*_*ari 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()
Run Code Online (Sandbox Code Playgroud)

  • `truncate` 默认为当前位置,因此不需要 `tell`。 (2认同)