2016-06-18 8 views
0

В основном я хочу скопировать комментарии из одного файла и добавить его к другим данным.Лучший способ «скопировать только комментарии из одного файла» и «добавить его в другой файл» с помощью python

Файл '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 output
Prepend line to beginning of a file
Python 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

+0

Эти комментарии в первом файле ... все они наверху или вам нужны все комментарии по всему файлу? – tdelaney

+0

@tdelaney Я хочу только комментарии (без данных) от input1 и помещать эти комментарии поверх ввода2 для создания вывода (такого же или отличного от input2). –

ответ

3

У вас уже есть отличный ответ с использованием временного каталога, но также просто создать временный файл в том же каталоге, что и целевой файл. В системах, где tmp - отдельная точка монтирования, вы избегаете дополнительной копии данных при переименовании временного файла. Обратите внимание, что нет промежуточного списка комментариев, который является значительным, если список комментариев большой.

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

... и теперь есть два :-) ... upvoted и мне нравится, что это В ответ в ответ отмечается дилемма «точка монтирования» для атомных движений. Благодарю. – Dilettant

2

Вы можете использовать lazy opening файла, а затем просто обработать первые строки файла до тех пор, не- комментарий найден, если ваши файлы содержат комментарии только в начале их. После нахождения строки, которая начинается без символа '#', вы можете просто выйти из цикла и позволить оператору python with обработать файл, закрывающий.

+0

Как сделать с ленивым открытием, любые подсказки? –

+0

Я думаю, что вопрос заключается не в обнаружении **, если ** для файла требуется добавить эти «комментарии», но как это сделать даже для больших файлов ... ср. мой ответ для «классического» способа ИМО, используя временный файл, например, в оболочке: 'cat comments_only test.txt >>/tmp/foo && mv/tmp/foo test.txt' – Dilettant

+0

О, извините, я неправильно понял вопрос, ваши файлы данных большие, и вы хотите добавить комментарии к нему, правильно? Нет способа для этого, не читая весь файл данных ... –

3

Особенно если файл данных (test.txt здесь) велико (как указано в ОП) Я хотел бы предложить (если файл открывается только для чтения и другой файл для записи):

  1. создать временную папку,
  2. предварительного заполнения временный файл там с зачищенных (!) строк комментария,
  3. добавить строки из файла данных,
  4. переименовать временный файл в файл данных,
  5. удалите временную папку и voil а.

Как так:

#! /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) 

Ничего особенного и на линии итерации может быть гм, ну ..., нужно измерить, если он достаточно мудр производительность.В сценариях, я должен был написать «сверху» файл, который в основном работал «хороший Nuff», или один использовал снаряд как:

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

PS: Для повышения файла чтение и запись в «добавить» фазе, следует использовать соответствующие блочные чтения и записи с блоками, оптимизированными для базовых системных вызовов, чтобы иметь максимальную производительность (поскольку это будет копия от одного до одного, нет необходимости в мультовой итерации линии).

2

Следуя идее Dilletant,

Для нескольких текстов и только один комментарий файл, который мы можем сделать это, используя скрипт:

# 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 

Это будет писать одни и те же комментарии ко всем из файлов (.txt) в каталоге.