Python解析后覆盖文件

时间:2011-05-19 17:48:49

标签: python parsing file overwrite

我是Python的新手,我需要做一个解析练习。我有一个文件,我需要解析它(只是标题),但是在这个过程之后,我需要保持文件格式相同,扩展名相同,并且在磁盘中的相同位置,但只有差异新标题..

我试过这段代码......

for line in open ('/home/name/db/str/dir/numbers/str.phy'):
    if line.startswith('ENS'):
        linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
        print linepars

..它完成了这项工作,但我不知道如何用新的解析“覆盖”文件。

5 个答案:

答案 0 :(得分:4)

最简单的方法,但不是最有效的(到目前为止,特别是对于长文件)将重写完整的文件。

您可以通过打开第二个文件句柄并重写每一行来完成此操作,但在标题的情况下,您将编写已解析的标题。例如,

fr = open('/home/name/db/str/dir/numbers/str.phy')
fw = open('/home/name/db/str/dir/numbers/str.phy.parsed', 'w') # Name this whatever makes sense

for line in fr:
    if line.startswith('ENS'):
        linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
        fw.write(linepars)
    else:
        fw.write(line)

fw.close()
fr.close()

编辑:请注意,这不使用readlines(),因此它的内存效率更高。它也不会存储每个输出行,而是一次只存储一个输出行,立即将其写入文件。

就像一个很酷的技巧,你可以在输入文件上使用with语句,以避免必须关闭它(Python 2.5 +):

fw = open('/home/name/db/str/dir/numbers/str.phy.parsed', 'w') # Name this whatever makes sense

with open('/home/name/db/str/dir/numbers/str.phy') as fr:
    for line in fr:
        if line.startswith('ENS'):
            linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
            fw.write(linepars)
        else:
             fw.write(line)

fw.close()

P.S。欢迎: - )

答案 1 :(得分:2)

正如其他人在这里所说,你想打开一个文件并使用该文件对象的.write()方法。

最好的方法是打开一个额外的文件进行写作:

import os

current_cfg = open(...)
parsed_cfg  = open(..., 'w')
for line in current_cfg:
    new_line = parse(line)
    print new_line
    parsed.cfg.write(new_line + '\n')
current_cfg.close()
parsed_cfg.close()

os.rename(....) # Rename old file to backup name
os.rename(....) # Rename new file into place

此外,我建议查看tempfile模块,并使用其中一种方法命名新文件或打开/创建它。我个人赞成将新文件放在与现有文件相同的目录中,以确保os.rename能够原子地工作(命名的配置文件将保证指向旧文件或新文件;否则它会指向部分写入/复制的文件。)

答案 2 :(得分:0)

以下代码完成工作 我的意思是它会覆盖文件ON ONESELF;这就是OP所要求的。这是可能的,因为转换只是删除字符,因此写入的文件指针 fo 始终是文件的指针 fi 读取。

import re

regx = re.compile('\AENS([A-Z]+)0+([0-9]{6})')

with open('bomo.phy','rb+') as fi, open('bomo.phy','rb+') as fo:
    fo.writelines(regx.sub('\\1\\2',line) for line in fi)

我认为写操作不是由操作系统一次一行执行,而是通过缓冲区执行。因此在写入转换行池之前会读取几行。这就是我的想法。

答案 3 :(得分:-1)

newlines = []
for line in open ('/home/name/db/str/dir/numbers/str.phy').readlines():
    if line.startswith('ENS'):
        linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
        newlines.append( linepars )
open ('/home/name/db/str/dir/numbers/str.phy', 'w').write('\n'.join(newlines))

答案 4 :(得分:-1)

(旁注:当然如果您正在使用大型文件,您应该知道所需的优化级别可能取决于您的情况。本质上Python非常非延迟评估。以下解决方案不是很好选择是否要解析大型文件,例如数据库转储或日志,但是一些调整(例如嵌套with子句并使用延迟生成器或逐行算法)可以允许O(1) - 内存行为。)

targetFile = '/home/name/db/str/dir/numbers/str.phy'

def replaceIfHeader(line):
    if line.startswith('ENS'):
        return re.sub('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
    else:
        return line

with open(targetFile, 'r') as f:
    newText = '\n'.join(replaceIfHeader(line) for line in f)

try:
    # make backup of targetFile
    with open(targetFile, 'w') as f:
        f.write(newText)
except:
    # error encountered, do something to inform user where backup of targetFile is

编辑:感谢杰夫的建议