使用python“仅复制一个文件中的注释”和“将其添加到另一个文件中”的更好方法

Posted

技术标签:

【中文标题】使用python“仅复制一个文件中的注释”和“将其添加到另一个文件中”的更好方法【英文标题】:Better way to "copy only the comments from one file" and "prepend it into another file" using python 【发布时间】:2016-06-18 16:01:13 【问题描述】:

基本上我想从一个文件中复制 cmets 并将其添加到另一个数据中。

文件'data_with_comments.txt'可以从pastebin获取: http://pastebin.com/Tixij2yG

它看起来像这样:

# coating file for detector A/R
# column 1 is the angle of incidence (degrees)
# column 2 is the wavelength (microns)
# column 3 is the transmission probability
# column 4 is the reflection probability
      14.2000     0.300000  8.00000e-05     0.999920
      14.2000     0.301000  4.00000e-05     0.999960
      14.2000     0.302000  2.00000e-05     0.999980
      14.2000     0.303000  2.00000e-05     0.999980
      14.2000     0.304000  2.00000e-05     0.999980
      14.2000     0.305000  3.00000e-05     0.999970
      14.2000     0.306000  5.00000e-05     0.999950

现在,我有另一个数据文件 'test.txt',如下所示:

300.0 1.53345164121e-32
300.1 1.53345164121e-32
300.2 1.53345164121e-32
300.3 1.53345164121e-32
300.4 1.53345164121e-32
300.5 1.53345164121e-32

需要的输出:

# coating file for detector A/R
# column 1 is the angle of incidence (degrees)
# column 2 is the wavelength (microns)
# column 3 is the transmission probability
# column 4 is the reflection probability
300.0 1.53345164121e-32
300.1 1.53345164121e-32
300.2 1.53345164121e-32
300.3 1.53345164121e-32
300.4 1.53345164121e-32

一种方法是:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author    : Bhishan Poudel
# Date      : Jun 18, 2016


# Imports
from __future__ import print_function
import fileinput


# read in comments from the file
infile = 'data_with_comments.txt'
comments = []
with open(infile, 'r') as fi:
    for line in fi.readlines():
        if line.startswith('#'):
            comments.append(line)

# reverse the list
comments = comments[::-1]
print(comments[0])
#==============================================================================


# preprepend a list to a file
filename = 'test.txt'

for i in range(len(comments)):
    with file(filename, 'r') as original: data = original.read()
    with file(filename, 'w') as modified: modified.write(comments[i] + data)

这种方法需要多次打开文件,当数据文件很大时效率不高。

有没有更好的方法?

相关链接如下:Appending a list to the top of Pandas DataFrame outputPrepend line to beginning of a filePython f.write() at beginning of file?How can I add a new line of text at top of a file?Prepend a line to an existing file in Python

【问题讨论】:

第一个文件中的那些 cmets...它们都在顶部还是您希望所有 cmets 都通过整个文件? @tdelaney 我只想要来自 input1 的 cmets(无数据)并将这些 cmets 放在 input2 之上以创建输出(与 input2 相同或不同)。 【参考方案1】:

您已经使用临时目录获得了很好的答案,但是在与目标文件相同的目录中创建一个临时文件也很常见。在 tmp 是单独挂载点的系统上,重命名临时文件时可以避免额外的数据副本。请注意,如果评论列表很大,则没有重要的 cmets 中间列表。

import os
import shutil

infile = 'data_with_comments.txt'
filename = 'test.txt'

tmpfile = filename + '.tmp'

try:
    # write wanted data to tempfile
    with open(tmpfile, 'w') as out_fp:
        # prepend comments from infle
        with open(infile) as in_fp:
            out_fp.writelines(filter(lambda l: l.startswith('#'), in_fp))
        # then add filename
        with open(filename) as in2_fp:
            shutil.copyfileobj(in2_fp, out_fp)
    # get rid of original data
    os.remove(filename)
    # replace with new data
    os.rename(tmpfile, filename)
finally:
    # cleanup on error
    if os.path.exists(tmpfile):
        os.remove(tmpfile)

【讨论】:

... 现在有两个:-) ... 赞成,我喜欢这个答案的介绍指出原子移动的“安装点”困境。谢谢。【参考方案2】:

特别是如果数据文件(此处为 test.txt)很大(如 OP 所述),我建议(该文件仅打开一次用于读取,另一个文件用于写入):

    创建一个临时文件夹, 在其中预填充一个带有已剥离(!)注释行的临时文件, 添加数据文件中的行, 将临时文件重命名为数据文件, 删除临时文件夹,瞧。

像这样:

#! /usr/bin/env python
from __future__ import print_function

import os
import tempfile


infile = 'data_with_comments.txt'
comments = None
with open(infile, 'r') as f_i:
    comments = [t.strip() for t in f_i.readlines() if t.startswith('#')]

file_name = 'test.txt'
file_path = file_name  # simpl0ification here

tmp_dir = tempfile.mkdtemp()  # create tmp folder (works on all platforms)
tmp_file_name = '_' + file_name  # determine the file name in temp folder

s_umask = os.umask(0077)

tmp_file_path = os.path.join(tmp_dir, tmp_file_name)
try:
    with open(file_path, "rt") as f_prep, open(
            tmp_file_path, "wt") as f_tmp:
        f_tmp.write('\n'.join(comments) + '\n')
        for line in f_prep.readlines():
            f_tmp.write(line)
except IOError as e:
    print(e)  # or what you want to tell abnout it, instead of aborting
else:
    os.rename(tmp_file_path, file_path)
finally:
    try:  # so we have an empty folder in - nearly - any case
        os.remove(tmp_file_path)
    except OSError:
        pass
    os.umask(s_umask)
    os.rmdir(tmp_dir)

没有什么花哨的,每行迭代可能是咳咳,嗯......,应该衡量它是否足够的性能明智。在某些情况下,我必须写入文件的“顶部”,这主要是“很好的”,或者使用类似的外壳:

cat comments_only test.txt > foo && mv foo test.txt

PS:为了在“追加”阶段提高文件读写速度,应该使用匹配的块级读取和写入,并针对底层系统调用优化块大小以获得最佳性能(因为这将是一对一的副本,所以有无需逐行迭代)。

【讨论】:

【参考方案3】:

您可以使用文件的lazy opening,然后只处理文件的第一行,直到您的文件仅在开头包含 cmets 时找到非注释。在找到没有“#”字符开头的行后,您可以从循环中中断并让 python 的with 语句处理文件关闭。

【讨论】:

懒打开怎么办,有什么提示吗? 我认为问题不在于检测 if 文件是否需要在这些“注释”行之前添加,而是如何针对大文件执行此操作... cf。我对 IMO“经典”方式的回答,通过使用 shell 中的临时文件:cat comments_only test.txt >> /tmp/foo && mv /tmp/foo test.txt 抱歉,我看错了问题,你的数据文件很大,你想在它前面加上 cmets,对吧?如果不读取整个数据文件,就没有办法... This 回答您关于懒惰阅读的问题。 您的方法也会多次重新读取原始文件。转换这部分:` for i in range(len(cmets)): with file(filename, 'r') as original: data = original.read() with file(filename, 'w') as modified: modified.write (cmets[i] + data) ` to this: ` with file(filename, 'r') as original: data = original.read() for i in range(len(cmets)): with file(filename, 'w ') 修改后的: modified.write(cmets[i] + data)`【参考方案4】:

遵循Dilletant的理念,

对于多个文本且只有一个注释文件,我们可以使用 shell 脚本来做到这一点:

# in the directory i have one file called   : comment
# and, other many files with file_extension : .txt

for file in *.txt; do cat comments "$file" > foo && mv foo "$file"; done

这会将相同的 cmets 写入目录中的所有文件(.txt)。

【讨论】:

以上是关于使用python“仅复制一个文件中的注释”和“将其添加到另一个文件中”的更好方法的主要内容,如果未能解决你的问题,请参考以下文章

下载一个 zip 文件并使用 Python3 将其提取到内存中

使用python从bigquery处理大量数据集,将其加载回bigquery表

SWIG:将其参数从 c++ 修改为 python 的函数

如何使用 python 和 pandas 将 Csv 文件转换为 libsvm?

Python functools.partial - 如何使用静态装饰器将其应用于类方法

用于访问 csv 文件中的值并使用 wamp 将其存储到数据库中的 python 程序