【问题标题】:Replacing a line on Python在 Python 上替换一行
【发布时间】:2012-12-09 10:30:47
【问题描述】:

我正在尝试将 PHP 代码转换为 Python,但在替换行时遇到了问题。尽管我发现使用 Python 更容易,但我完全迷失了;我可以找到要替换的行,我可以在行尾添加一些内容,但我无法在文件上再次写入该行。

file = open("cache.ucb", 'rb')
for line in file:
   if line.split('~!')[0] == ex[4]:
       line += "~!" + mask[0]
       line = line.rstrip() + "\n"
       # Write on the file here!

基本上,file 使用~! 作为分隔符,我阅读每一行。如果以~! 分隔的第一个token 行以ex[4] 开头,例如Catbuntu,我想追加mask[0],可以是Bousie,在该行的末尾。然后我删除新行字符并在末尾添加一个。

这就是问题所在。我想按原样编写文件,但只更改该行。这可能吗?

【问题讨论】:

  • 正如 Droogans 所提到的,除非您有明确的理由以二进制形式读取数据,否则您通常最好省略调用 open() 的标志。

标签: python file replace


【解决方案1】:

你没有打开你的文件来写。

file = open("cache.ucb", 'rb')

这一行打开一个文件以二进制模式读取。你也需要打开它来写。

尝试以写入模式打开文件,'w' 并写回该行。

或者您可以简单地在开头打开文件进行读/写,然后在循环中写入:

file = open("cache.ucb", 'a+')

【讨论】:

  • 他试图“按原样写入文件,但只更改该行”——而不是保留该行的长度。你不能就地这样做。
【解决方案2】:

以 'wb' 模式打开文件并将file.write(line) 放在循环的末尾。

【讨论】:

    【解决方案3】:

    假设您使用的是 python >=2.7,以下应该可以解决问题

    original = open(filename)
    newfile = []
    for line in original:
        if line.split('~!')[0] == ex[4]:
            line += "~!" + mask[0]
            line = line.rstrip() + "\n"
        newfile.append(line)
    original.close()
    amended.open(filename, "w")
    amended.writeLines(newfile)
    amended.close()
    

    如果出于某种原因您使用的是 python 2.6 或更低版本,请将倒数第二行替换为:

    amended.write("".join(newfile))
    

    编辑:修复了替换从问题中复制的错误,提取文件名。

    【讨论】:

    • 谢谢!它奏效了,尽管我不得不修改一些东西。我编辑了答案...谢谢!
    • 我假设你想要for line in file:,而不是for line as file:。 (OP的问题也有同样的问题。)
    • 是的,在复制之前应该检查过 OPs 代码。
    • 哦,我看到我在问题的代码上犯了错误,很抱歉假设它们是你的:P(愚蠢的问题:所有人都在谈论的 OP 是什么?)
    【解决方案4】:

    您不能就地修改文件,至少如果您想在一行中插入字符则不能。你最终会覆盖下一行的开头。

    有两种不同的方法可以做到这一点:

    1. 将文件读入内存,关闭它,然后写回新版本。
    2. 边写边写一个新的临时文件,然后把它移到原来的版本上。

    那么,您如何在它们之间进行选择?我将尝试总结差异,按顺序排列,以便在重要的情况下,每个差异通常都优于下面的差异(但这只是“通常”——您必须考虑自己的用例):

    • 2 不需要将整个内容保存在内存中。如果你的文件有 20GB 长,这显然是一个巨大的胜利;如果是 16KB,没关系。

    • 2 使整个操作原子化。即使它中途失败,或者其他进程在您更改文件时尝试读取文件,任何人都无法看到一些无效的半修改文件;他们将看到原始文件或新文件。

    • 2 需要一些可用磁盘空间(因为暂时同时有两个文件副本)。

    • 如果您同时关心 Windows 和 POSIX,2 将是一个巨大的痛苦。

    • 2 如果原始文件和临时目录位于不同的文件系统上,则可能涉及跨文件系统复制,除非您对此非常小心。

    • 如果以上两个都不是问题,

      2 会更简单。

    Drakekin 的回答告诉你如何做 #1。

    如果您不关心 Windows 或跨文件系统问题,请按照以下方法执行 #2:

    infile = open("cache.ucb", 'rb')
    outfile = tempfile.NamedTemporaryFile(delete=False)
    for line in infile:
       if line.split('~!')[0] == ex[4]:
           line += "~!" + mask[0]
           line = line.rstrip() + "\n"
       outfile.write(line)
    infile.close()
    os.rename(outfile.name, "cache.ucb")
    outfile.close()
    

    您可以通过例如将dir=os.path.dirname(original path) 传递给NamedTemporaryFile 构造函数来解决跨文件系统问题,但前提是您确定始终有权在原始文件旁边创建新文件(即'并不总是保证,只是因为您有权重写原始文件——UNIX 权限、Windows ACL、OS X 沙箱等都提供了可能是错误的方法)。

    要解决 Windows 问题……好吧,从 Is an atomic file rename (with overwrite) possible on Windows 开始,以及互联网上的类似讨论。

    【讨论】:

    • 出于兴趣,在实践中将新版本保存在内存中或临时文件中有什么区别?
    • @Drakekin:我会更新答案,而不是试图在评论中回答。
    • 感谢您花时间解释。
    猜你喜欢
    • 2013-02-25
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-07
    • 1970-01-01
    相关资源
    最近更新 更多