Python объединяет текстовые файлы
у меня есть список из 20 имен файлов, как ['file1.txt', 'file2.txt', ...]. Я хочу написать скрипт Python для объединения этих файлов в новый файл. Я мог бы открыть каждый файл по f = open(...), читать строку за строкой, вызывая f.readline(), и запишите каждую строку в этот новый файл. Это не кажется мне очень "элегантным", особенно та часть, где я должен читать//писать строку за строкой.
есть ли более "элегантный" способ сделать это в Python?
11 ответов:
это должно помочь
для больших файлов:
filenames = ['file1.txt', 'file2.txt', ...] with open('path/to/output/file', 'w') as outfile: for fname in filenames: with open(fname) as infile: for line in infile: outfile.write(line)для небольших файлов:
filenames = ['file1.txt', 'file2.txt', ...] with open('path/to/output/file', 'w') as outfile: for fname in filenames: with open(fname) as infile: outfile.write(infile.read())... и еще один интересный, о котором я подумал:
filenames = ['file1.txt', 'file2.txt', ...] with open('path/to/output/file', 'w') as outfile: for line in itertools.chain.from_iterable(itertools.imap(open, filnames)): outfile.write(line)к сожалению, этот последний метод оставляет несколько открытых файловых дескрипторов, о которых GC должен позаботиться в любом случае. Я просто подумал, что это интересно
использовать
shutil.copyfileobj. Это должно быть более эффективно.with open('output_file.txt','wb') as wfd: for f in ['seg1.txt','seg2.txt','seg3.txt']: with open(f,'rb') as fd: shutil.copyfileobj(fd, wfd, 1024*1024*10) #10MB per writing chunk to avoid reading big file into memory.
именно так fileinput для:
import fileinput with open(outfilename, 'w') as fout, fileinput.input(filenames) as fin: for line in fin: fout.write(line)для этого случая использования это действительно не намного проще, чем просто перебирать файлы вручную, но в других случаях очень удобно иметь один итератор, который перебирает все файлы, как если бы они были одним файлом. (Кроме того, тот факт, что
fileinputзакрывает каждый файл, как только это сделано, значит не нужноwithилиcloseкаждый из них, но это всего лишь однострочная экономия, не такая большая сделка.)есть некоторые другие полезные функции в
fileinput, как и возможность делать модификации файлов на месте, просто фильтруя каждую строку.
как отмечено в комментариях, так и обсуждается в другом post,
fileinputдля Python 2.7 не будет работать, как указано. Вот небольшая модификация, чтобы сделать код Python 2.7 уступчивыйwith open('outfilename', 'w') as fout: fin = fileinput.input(filenames) for line in fin: fout.write(line) fin.close()
Я не знаю насчет элегантности, но это работает:
import glob import os for f in glob.glob("file*.txt"): os.system("cat "+f+" >> OutFile.txt")
что случилось с UNIX командами ? (учитывая, что вы не работаете на Windows):
ls | xargs cat | tee output.txtвыполняет задание (вы можете вызвать его из python с подпроцессом, если хотите)
Если файлы не гигантские:
with open('newfile.txt','wb') as newf: for filename in list_of_files: with open(filename,'rb') as hf: newf.write(hf.read()) # newf.write('\n\n\n') if you want to introduce # some blank lines between the contents of the copied filesЕсли файлы слишком велики для полного чтения и хранения в ОЗУ, алгоритм должен быть немного другим, чтобы читать каждый файл, который будет скопирован в цикле кусками фиксированной длины, используя
read(10000)например.
Если у вас много файлов в каталоге, тут
glob2может быть лучшим вариантом для создания списка файлов, а не писать их от руки.import glob2 filenames = glob2.glob('*.txt') # list of all .txt files in the directory with open('outfile.txt', 'w') as f: for file in filenames: with open(file) as infile: f.write(infile.read()+'\n')
outfile.write(infile.read()) 2.1085190773010254s shutil.copyfileobj(fd, wfd, 1024*1024*10) 0.60599684715271sпростой тест показывает, что shutil работает лучше.
проверить .метод read () объекта File:
http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects
вы могли бы сделать что-то вроде:
concat = "" for file in files: concat += open(file).read()или более "элегантный" python-way:
concat = ''.join([open(f).read() for f in files])который, согласно этой статье:http://www.skymind.com/~ocrow/python_string/ также будет самым быстрым.
def concatFiles(): path = 'input/' files = os.listdir(path) for idx, infile in enumerate(files): print ("File #" + str(idx) + " " + infile) concat = ''.join([open(path + f).read() for f in files]) with open("output_concatFile.txt", "w") as fo: fo.write(path + concat) if __name__ == "__main__": concatFiles()
альтернатива @inspectorG4dget answer (лучший ответ на сегодняшний день 29-03-2016). Я тестировал с 3 файлами 436MB.
@inspectorG4dget решение: 162 секунды
следующее решение : 125 секунд
from subprocess import Popen filenames = ['file1.txt', 'file2.txt', 'file3.txt'] fbatch = open('batch.bat','w') str ="type " for f in filenames: str+= f + " " fbatch.write(str + " > file4results.txt") fbatch.close() p = Popen("batch.bat", cwd=r"Drive:\Path\to\folder") stdout, stderr = p.communicate()идея в том, чтобы создать пакетный файл и выполнить его, воспользовавшись "старые добрые технологии". Его полу-питон, но работает быстрее. Работает для Windows.
Comments