【问题标题】:Is it possible to modify lines in a file in-place?是否可以就地修改文件中的行?
【发布时间】:2011-03-27 23:39:58
【问题描述】:

是否可以逐行解析文件,并在遍历这些行时就地编辑一行?

【问题讨论】:

  • 在某些条件下是可能的。如果编辑处理的行所产生的行较短或与处理的行相同,则很容易做到。如果不是这种情况,它会变得更加困难,尽管如果经过编辑的行不是太多的话,这并非不可能。你问这个是因为你想处理一个大文件吗?
  • >>> f = open('tmp', 'r+') >>> f.readline() '75.14\n' >>> f.readline() '100\n' > >> l = _ >>> f.seek(-l.len(), file.SEEK_CUR) >>> f.seek(-len(l), os.SEEK_CUR) >>> f.write('999\ n') >>> f.close() >>>
  • 在此处查看示例 (stackoverflow.com/questions/5286020/…)
  • 我们可以用 bash 做吗?

标签: python file-io


【解决方案1】:

是否可以逐行解析文件,并在遍历这些行时就地编辑一行?

可以像 stdlib 的 fileinput module 那样使用备份文件进行模拟。

这是一个示例脚本,它从命令行或stdin 给出的文件中删除不满足some_condition 的行:

#!/usr/bin/env python
# grep_some_condition.py
import fileinput

for line in fileinput.input(inplace=True, backup='.bak'):
    if some_condition(line):
        print line, # this goes to the current file

例子:

$ python grep_some_condition.py first_file.txt second_file.txt

在完成时first_file.txtsecond_file.txt 文件将只包含满足some_condition() 谓词的行。

【讨论】:

  • 实际上不写入文件中间的方法也是明智的,因为它很容易使修改原子化(也就是说,如果文件最终不会处于部分修改状态,如果程序被中断)。
  • 啊,fileinput有一个files参数,docs.python.org/3/library/fileinput.html
【解决方案2】:

fileinput 模块的 API 非常丑陋,我为这项任务找到了漂亮的模块 - in_place,Python 3 的示例:

import in_place

with in_place.InPlace('data.txt') as file:
    for line in file:
        line = line.replace('test', 'testZ')
        file.write(line)

与文件输入的主要区别:

  • 不是劫持sys.stdout,而是返回一个新的文件句柄进行写入。
  • 文件句柄支持所有标准 I/O 方法,而不仅仅是readline()

重要提示

  1. 如果您不使用 file.write() 行重写文件,此解决方案会删除文件中的每一行。
  2. 此外,如果进程中断,您会丢失文件中尚未重写的任何行。

【讨论】:

    【解决方案3】:

    没有。您无法安全地写入正在阅读的文件,因为您对文件所做的任何更改都可能覆盖您尚未阅读的内容。为了安全地执行此操作,您必须将文件读入缓冲区,根据需要更新任何行,然后重新写入文件。

    如果您要逐字节替换文件中的内容(即,如果您要替换的文本与您要替换的新字符串的长度相同),那么您可以摆脱它,但是这是一个马蜂窝,所以我会省去你的麻烦,只需阅读完整的文件,替换内存中的内容(或通过临时文件),然后再写出来。

    【讨论】:

      【解决方案4】:

      如果您只打算执行不改变文件被修改部分长度的本地化更改(例如将所有字符更改为小写),那么您实际上可以动态覆盖文件的旧内容。

      为此,您可以通过file 对象的seek() 方法使用随机文件访问。

      或者,您可以使用mmap 对象将整个文件视为可变字符串。请记住,mmap 对象可能会在 32 位 CPU 上施加 2-4 GB 范围内的最大文件大小限制,具体取决于您的操作系统及其配置。

      【讨论】:

        【解决方案5】:

        您必须以字符为单位备份行的大小。假设您使用了readline,那么您可以获取该行的长度并使用:

        file.seek(offset[, whence])
        

        将whence设置为SEEK_CUR,将offset设置为-length

        请参阅Python Docs 或查看seek 的联机帮助页。

        【讨论】:

          猜你喜欢
          • 2013-07-27
          • 1970-01-01
          • 1970-01-01
          • 2020-02-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-17
          • 2020-03-20
          相关资源
          最近更新 更多