替换Python中的一行代码

3

我试图将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!

基本上,文件使用~!作为分隔符,并读取每一行。如果该行的第一个以~!分隔的标记ex[4]开头,例如Catbuntu,则希望在该行末尾添加mask[0],即Bousie。然后删除换行符并在行末添加一个新的换行符。
问题在于,我想将文件恢复成原样,但只更改那一行。这可行吗?

3
小心读写二进制数据 - yurisich
正如Droogans所提到的,除非你有明确的原因需要将数据读取为二进制格式,否则最好在调用open()时省略标志。 - Drakekin
4个回答

5
假设您使用的是 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))

编辑:已修复从问题中复制的错误,将文件名因素化。


谢谢!它起作用了,尽管我不得不修改一些东西。我编辑了答案...谢谢! - Addison Montgomery
我猜你想要的是 for line in file:,而不是 for line as file:。 (OP的问题也有同样的问题。) - abarnert
是的,在复制 vertabrim 的代码之前应该检查一下 OP 的代码。 - Drakekin
哦,我看到我在问题的代码上犯了错误,抱歉以为那是你的代码 :P (愚蠢的问题:所有人都在谈论什么是OP?) - Addison Montgomery

2
您无法直接修改文件,至少如果您想插入字符到一行中,就不能这样做。否则,您将覆盖下一行的开头。有两种不同的方法可以解决此问题:
1.将文件读入内存,关闭它,然后写回新版本。
2.在进行操作时编写一个新的临时文件,然后将其移动到原始版本上方。
那么,如何在它们之间进行选择?我将尝试总结差异,按照重要性排序(但这只是“通常”——您必须考虑自己的用例):
1.对于第二种方法,不需要将整个文件都保存在内存中。如果您的文件长度为20GB,则这显然是一个巨大的优势;如果它是16KB,则无关紧要。
2.第二种方法使整个操作具有原子性。即使它在一半失败,或者在你正在改变它的过程中,其他进程尝试读取该文件,也没有任何人能够看到一些无效的半修改文件;他们将看到原始文件或新文件。
3.第二种方法需要一些可用磁盘空间(因为同时有两个文件副本)。
4.如果您关心Windows和POSIX,则第二种方法会非常麻烦。
5.如果原始文件和临时目录位于不同的文件系统上,则第二种方法可能涉及复制。
6.如果上述两个问题都不是问题,则第二种方法更简单。
Drakekin的答案告诉您如何执行第一种方法。
如果您不关心Windows或跨文件系统问题,以下是如何执行第二种方法:
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 ACLs、OS X 沙箱等都可能导致该方法无效)。
要解决 Windows 问题... 首先请查看互联网上的 讨论 和类似问题。

2
有趣的是,在实践中,将新版本保存在内存中和保存在临时文件中有什么区别? - Drakekin
1
@Drakekin:我会更新答案,而不是试图在评论中回答。 - abarnert
感谢您抽出时间来解释。 - Drakekin

1

以'wb'模式打开文件,并在循环结束时加入file.write(line)


0

您没有打开文件进行写入。

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

这行代码以二进制模式打开一个文件进行读取。你还需要以写入模式打开它。

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

或者你可以在循环开始时直接以读/写模式打开文件,并在循环内部进行写入:

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

他试图“将文件写成原样,但只更改那一行”——而不保留该行的长度。你不能在原地完成这个任务。 - abarnert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接