【问题标题】:truncating a text file does not change the file截断文本文件不会更改文件
【发布时间】:2016-04-23 19:44:17
【问题描述】:

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

【问题讨论】:

  • 您正在从文件末尾截断,因此您需要寻找文件中的正确位置,例如file.seek(0); file.truncate()
  • @SirParselot 我想在“CC”之后截断文件,在file.seek(0)之后,整个信息都会消失!
  • 这就是为什么我说了类似的话。您需要在 CC 之后立即在文件中找到该点并找到该点
  • @SirParselot 也许我的期望是错误的,但我希望在每次读取一行时移动当前位置并在读取“CC”后截断文件(因为当前位置变为“正确" 位置)

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


【解决方案1】:

看起来您正在成为 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()

【讨论】:

    【解决方案2】:

    除了 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()
    

    【讨论】:

    • truncate 默认为当前位置,因此 tell 不是必需的。
    • 我是这么认为的,但是在我的脚本中,它不起作用并且什么也没删除。给它任何位置,它在那之后立即被截断。
    • 这很奇怪,在我的测试中没有 tell 时它工作得很好。
    • 对不起,我在 Python 3 中。在 Python 2 中,它没有按预期工作。似乎有所作为。
    • 是的,我可以重现。不知道该怎么做...似乎它一定是一个错误,因为 Python 3 文档仍然表明它应该默认为当前位置。
    猜你喜欢
    • 2017-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多