在Python中为现有文件预先添加一行

在Python中为现有文件预先添加一行,python,prepend,Python,Prepend,我需要在文本文件的第一行添加一行代码,看起来我唯一可用的选项是比python中预期的更多的代码行。大概是这样的: f = open('filename','r') temp = f.read() f.close() f = open('filename', 'w') f.write("#testfirstline") f.write(temp) f.close() 没有更简单的办法吗?此外,与打开单个句柄进行读写('r+')相比,我更经常看到这个双句柄示例-这是为什么?您可以使用以下命令保

我需要在文本文件的第一行添加一行代码,看起来我唯一可用的选项是比python中预期的更多的代码行。大概是这样的:

f = open('filename','r')
temp = f.read()
f.close()

f = open('filename', 'w')
f.write("#testfirstline")

f.write(temp)
f.close()

没有更简单的办法吗?此外,与打开单个句柄进行读写('r+')相比,我更经常看到这个双句柄示例-这是为什么?

您可以使用以下命令保存一个写调用:

f.write('#testfirstline\n' + temp)

使用“r+”时,您必须在读取后和写入前倒带文件。

一种可能性是:

import os
open('tempfile', 'w').write('#testfirstline\n' + open('filename', 'r').read())
os.rename('tempfile', 'filename')
其他办法:

with open("infile") as f1:
    with open("outfile", "w") as f2:
        f2.write("#test firstline")
        for line in f1:
            f2.write(line)
或一行:

open("outfile", "w").write("#test firstline\n" + open("infile").read())
感谢有机会思考这个问题:)


Cheers

Python使许多事情变得简单,并包含用于许多常见操作的库和包装器,但目标不是隐藏基本事实

您在这里遇到的基本事实是,在不重写整个结构的情况下,通常无法将数据前置到现有的平面结构。无论使用何种语言,都是如此


有几种方法可以保存文件句柄或降低代码的可读性,其中许多方法在其他答案中提供,但没有一种方法可以改变基本操作:必须先读取现有文件,然后写出要预写的数据,然后再写入读取的现有数据


务必保存文件句柄,但不要将此操作打包为尽可能少的代码行。事实上,永远不要去寻找最少的代码行——这是混淆,而不是编程。

我会坚持单独读写,但我们当然可以更简洁地表达每一行:

蟒蛇2:

with file('filename', 'r') as original: data = original.read()
with file('filename', 'w') as modified: modified.write("new first line\n" + data)
蟒蛇3:

with open('filename', 'r') as original: data = original.read()
with open('filename', 'w') as modified: modified.write("new first line\n" + data)

注意:file()函数在python3中不可用。

此函数不将整个文件读入内存,但在Windows上可能不起作用

def prepend_line(path, line):
    with open(path, 'r') as old:
        os.unlink(path)
        with open(path, 'w') as new:
            new.write(str(line) + "\n")
            shutil.copyfileobj(old, new)

我认为这是一个清晰而灵活的三层衬里。它使用list.insert函数,因此如果您确实想在文件前加前缀,请使用l.insert(0,'insert_str')。当我为正在开发的Python模块实际执行此操作时,我使用了l.insert(1,“insert_str”),因为我想跳过第0行的“#--coding:utf-8--”字符串。这是代码

f = open(file_path, 'r'); s = f.read(); f.close()
l = s.splitlines(); l.insert(0, 'insert_str'); s = '\n'.join(l)
f = open(file_path, 'w'); f.write(s); f.close()

如果您希望在文件中的特定文本后加上前缀,则可以使用下面的函数

def prepend_text(file, text, after=None):
    ''' Prepend file with given raw text '''
    f_read = open(file, 'r')
    buff = f_read.read()
    f_read.close()
    f_write = open(file, 'w')
    inject_pos = 0
    if after:
        pattern = after
        inject_pos = buff.find(pattern)+len(pattern)
    f_write.write(buff[:inject_pos] + text + buff[inject_pos:])
    f_write.close()
因此,首先打开文件,读取并将其全部保存到一个字符串中。
然后,我们尝试在字符串中找到发生注入的字符号。然后,通过一次写入和对字符串的一些智能索引,我们现在可以重写整个文件,包括注入的文本。

我没有看到什么,或者我们不能使用足够大的缓冲区来读取输入文件的部分内容(而不是全部内容)使用此缓冲区,在文件打开时遍历文件,并继续交换文件缓冲区内容


这似乎比在内存中读取整个内容、在内存中修改内容并将其写回同一个文件或(更糟糕的是)另一个文件要高效得多(尤其是对于大文件)。很抱歉,现在我没有时间实现一个示例代码段,我稍后会继续讨论这个问题,但也许你会明白这个想法。

+1,尽管你可以通过执行
f.write('#testfirstline\n'+temp)
来保存整行代码,但我建议你使用
f.writelines(('#testfirstline\n',tmp))
。然后,如果temp是巨大的,那么您不会为了写出这些内容而创建另一个巨大的字符串。或者,只需使用OP中的额外写入行……这在POSIX上是不安全的(我相信某些文件系统、XFS上的竞争条件)。在重命名之前,需要对临时文件调用f.flush()和os.fsync(f.fileno())。“永远不要寻找最少的代码行——这是混淆,而不是编程”——隐藏执行函数所需的时间不是混淆,而是抽象。如果代码的目的是按照一定比例的时间来读取和运行,那么代码的结构将与实际结构完全不同。“您必须读取现有文件,然后写出您要预写的数据,然后再写入您读取的现有数据”-这不是真的,对读写操作进行分块和交织可以提高内存效率,这样文件的完整内容就不需要一次驻留在内存中。处理这些细节实际上是一个很好的库。请注意,
file()
-函数在Python 3中不可用,仅在版本2中可用。在Python3中,只需将其替换为
open()
。实际上,您也不应该在Python2中使用file函数。您应该始终使用任一Python中的
open()
函数打开文件。文件功能只是出于历史原因才存在。@HenrySchreiner当时,我觉得
file
更直观,不管社区共识和通用风格指南如何。但是当3.x出现时(我是一个相当热心的采用者FWIW),我没有更多的选择:)我喜欢这样,尽管你必须小心,因为如果中断会导致数据丢失。这样做会覆盖文件。是否可以使用
shutil.copyfileobj
而不是覆盖来创建新文件?抱歉@alvas我不太明白你的意思。如果你想写入一个新文件,只需在第二次调用
open
时添加一个不同的
路径即可(值得注意的是:你最好逐行读取文件并写入临时文件。完成后,删除原始文件并替换为临时文件。)你可以把它做成一个一行的牙套,它可以打印出汉字!嗨,Ulf Gjerdingen!文件是否包含中文字符?
def prepend_text(file, text, after=None):
    ''' Prepend file with given raw text '''
    f_read = open(file, 'r')
    buff = f_read.read()
    f_read.close()
    f_write = open(file, 'w')
    inject_pos = 0
    if after:
        pattern = after
        inject_pos = buff.find(pattern)+len(pattern)
    f_write.write(buff[:inject_pos] + text + buff[inject_pos:])
    f_write.close()