Python 解析后覆盖文件



我是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

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

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

您可以通过打开第二个文件句柄并重写每一行来执行此操作,除了标头的情况,您将写入解析的标头。 例如

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

附言欢迎:-)

正如其他人在这里所说的那样,您想打开一个文件并使用该文件对象的.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原子地工作(命名的配置文件将保证指向旧文件或新文件;在任何情况下都不会指向部分写入/复制的文件)。

以下代码完成这项工作。
我的意思是它确实会覆盖自己的文件;这就是OP所要求的。这是可能的,因为转换只是删除字符,因此写入的文件指针始终位于读取的文件指针 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)

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

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

(旁注:当然,如果您正在处理大文件,您应该意识到所需的优化级别可能取决于您的情况。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

编辑:感谢杰夫的建议

相关内容

  • 没有找到相关文章

最新更新