在Python中搜索并替换文件中的一行

377 投票
13 回答
630471 浏览
提问于 2025-04-10 23:32

我想要遍历一个文本文件的内容,对某些行进行查找和替换,然后把结果写回文件。我可以先把整个文件加载到内存中,然后再写回去,但这样做可能不是最好的方法。

在下面的代码中,最好的做法是什么呢?

f = open(file)
for line in f:
    if line.contains('foo'):
        newline = line.replace('foo', 'bar')
        # how to write this newline back to the file

13 个回答

99

这里有另一个经过测试的例子,它可以匹配搜索和替换的模式:

import fileinput
import sys

def replaceAll(file,searchExp,replaceExp):
    for line in fileinput.input(file, inplace=1):
        if searchExp in line:
            line = line.replace(searchExp,replaceExp)
        sys.stdout.write(line)

使用示例:

replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")
309

最简单的方法可能就是使用 fileinput 模块。比如,下面的代码可以在文件中直接添加行号:

import fileinput

for line in fileinput.input("test.txt", inplace=True):
    print('{} {}'.format(fileinput.filelineno(), line), end='') # for Python 3
    # print "%d: %s" % (fileinput.filelineno(), line), # for Python 2

这里发生的事情是:

  1. 原始文件会被移动到一个备份文件中
  2. 在循环中,标准输出会被重定向回原始文件
  3. 因此,任何 print 语句的输出都会写回到原始文件中

fileinput 还有更多的功能。例如,它可以自动处理 sys.args[1:] 中的所有文件,而不需要你手动一个一个去处理。从 Python 3.2 开始,它还提供了一个方便的上下文管理器,可以在 with 语句中使用。


虽然 fileinput 对于临时脚本来说很不错,但我会对在正式代码中使用它有所保留,因为它的可读性和熟悉度确实不高。在实际的(生产)代码中,花几行代码让过程变得明确,这样代码会更容易理解。

有两种选择:

  1. 如果文件不大,你可以把它全部读入内存。然后关闭文件,重新以写入模式打开它,把修改后的内容写回去。
  2. 如果文件太大,无法全部存入内存,你可以把它移动到一个临时文件中,逐行读取,然后写回到原始文件中。注意,这样需要两倍的存储空间。
235

我想这样的代码应该可以做到。它的基本功能是把内容写入一个新文件,然后用这个新文件替换掉旧文件:

from tempfile import mkstemp
from shutil import move, copymode
from os import fdopen, remove

def replace(file_path, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    with fdopen(fh,'w') as new_file:
        with open(file_path) as old_file:
            for line in old_file:
                new_file.write(line.replace(pattern, subst))
    #Copy the file permissions from the old file to the new file
    copymode(file_path, abs_path)
    #Remove original file
    remove(file_path)
    #Move new file
    move(abs_path, file_path)

撰写回答