【问题标题】:Prepend a line to an existing file in Python在 Python 中的现有文件前添加一行
【发布时间】:2011-05-26 03:42:08
【问题描述】:

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

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

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

f.write(temp)
f.close()

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

【问题讨论】:

  • (值得注意的是:您最好逐行读取文件并写入临时文件。完成后,删除原始文件并替换为临时文件。)

标签: python prepend


【解决方案1】:

我没有看到什么或者我们不能只使用一个足够大的缓冲区来读入输入文件部分(而不是整个内容)并使用这个缓冲区遍历文件当它打开时并继续交换文件缓冲区内容?

这似乎比读取内存中整个内容、修改它内存更有效(尤其是对于大文件) 并将其写回同一个文件,或者(甚至更糟)不同的文件。抱歉,现在我没有时间实现示例 sn-p,我稍后再讨论,但也许你明白了。

【讨论】:

    【解决方案2】:

    我会坚持单独的读取和写入,但我们当然可以更简洁地表达:

    Python2:

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

    Python3:

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

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

    【讨论】:

    • 请注意file()-函数在 Python 3 中不可用,仅在版本 2 中可用。只需在 Python 3 中将其替换为 open()
    • 其实在 Python 2 中也不应该使用 file 函数。您应该始终在任一 Python 中使用 open() 函数打开文件。文件功能只是出于历史原因。
    • @HenrySchreiner 当时我觉得file 更直观,不管社区共识和通用风格指南。但是当 3.x 出现时(我是一个相当热心的 FWIW 采用者),我再也没有选择了 :)
    【解决方案3】:

    如果您希望在特定文本之后添加到文件中,则可以使用以下函数。

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

    所以首先你打开文件,阅读它并将它全部保存到一个字符串中。 然后我们尝试在字符串中查找将发生注入的字符编号。然后通过一次写入和对字符串的一些智能索引,我们现在可以重写整个文件,包括注入的文本。

    【讨论】:

      【解决方案4】:

      这是一个我认为清晰灵活的 3 班轮。它使用 list.insert 函数,所以如果你真的想添加到文件中,请使用 l.insert(0, 'insert_str')。当我实际为我正在开发的 Python 模块执行此操作时,我使用了 l.insert(1, 'insert_str') 因为我想跳过 '# -- coding: utf-8 --'第 0 行的字符串。这是代码。

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

      【讨论】:

      • 你也可以把它做成 1-liner
      • 这个打印出汉字!
      • 嗨,乌尔夫·杰丁根!文件是否包含汉字?
      【解决方案5】:

      这可以在不将整个文件读入内存的情况下完成这项工作,尽管它可能无法在 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)
      

      【讨论】:

      • 我喜欢这个,不过要小心,如果中断会导致数据丢失。
      • 这样做会覆盖文件。是否可以使用shutil.copyfileobj 创建新文件而不是覆盖?
      • 对不起@alvas 我不太明白你的意思。如果您想写入新文件,只需在第二次调用 open 时添加不同的 path
      【解决方案6】:

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

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

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

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

      【讨论】:

      • “永远不要去寻找最少的代码行——那是混淆,而不是编程”——隐藏执行功能所需的时间不是混淆,而是抽象。如果代码的目的是花费一定比例的时间来阅读和运行,那么代码将具有与实际完全不同的结构。
      • “你必须读入现有文件,然后写出你想要添加的数据,然后是你读入的现有数据”——这不是真的,它可能会占用更多内存——有效地对读写操作进行分块和交错,这样文件的全部内容就不需要一次驻留在内存中。处理这些细节实际上会成为一个优秀的库。
      【解决方案7】:
      with open("file", "r+") as f: s = f.read(); f.seek(0); f.write("prepend\n" + s)
      

      【讨论】:

        【解决方案8】:

        其他方法:

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

        感谢有机会思考这个问题:)

        干杯

        【讨论】:

          【解决方案9】:

          一种可能性如下:

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

          【讨论】:

          • 这在 POSIX 上是不安全的(某些文件系统上的竞争条件,我相信 XFS)。重命名前需要在临时文件上调用 f.flush() 和 os.fsync(f.fileno())。
          【解决方案10】:

          你可以用这个来保存一个写调用:

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

          使用 'r+' 时,您必须在读取后和写入前回退文件。

          【讨论】:

          • +1,虽然你可以通过 f.write('#testfirstline\n' + temp) 保存一整行代码
          • 我会推荐f.writelines(('#testfirstline\n',tmp))。然后,如果 temp 很大,您就不会创建另一个巨大的字符串来将其全部写出来。或者,只需使用 OP 中的额外写入行...
          猜你喜欢
          • 1970-01-01
          • 2013-03-27
          • 2016-05-23
          • 2016-04-05
          • 1970-01-01
          • 2017-05-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多