我有一个包含20个文件名的列表,例如['file1.txt', 'file2.txt', ...]
。我想编写一个Python脚本来将这些文件连接到一个新文件中。我可以通过f = open(...)
打开每个文件,通过调用f.readline()
逐行读取,并将每行写入该新文件。它对我来说似乎不是很“优雅”,尤其是我必须阅读的部分//逐行写。
在Python中有更“优雅”的方法吗?
答案 0 :(得分:216)
这应该这样做
适用于大型文件:
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无论如何都要照顾它们。我只是觉得它很有趣
答案 1 :(得分:149)
使用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)
答案 2 :(得分:51)
这正是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中进行了讨论,Python 2.7的fileinput
将无法正常工作。这里稍作修改,使代码符合Python 2.7
with open('outfilename', 'w') as fout:
fin = fileinput.input(filenames)
for line in fin:
fout.write(line)
fin.close()
答案 3 :(得分:8)
我不了解优雅,但这很有效:
import glob
import os
for f in glob.glob("file*.txt"):
os.system("cat "+f+" >> OutFile.txt")
答案 4 :(得分:5)
UNIX命令有什么问题? (鉴于你没有在Windows上工作):
ls | xargs cat | tee output.txt
完成这项工作(如果需要,可以使用子进程从python中调用它)
答案 5 :(得分:2)
查看File对象的.read()方法:
http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects
您可以执行以下操作:
concat = ""
for file in files:
concat += open(file).read()
或更'优雅'的蟒蛇方式:
concat = ''.join([open(f).read() for f in files])
根据这篇文章:http://www.skymind.com/~ocrow/python_string/也是最快的。
答案 6 :(得分:2)
@ inspectorG4dget答案的替代方案(日期为29-03-2016的最佳答案)。我测试了3个436MB的文件。
@ inspectorG4dget解决方案:162秒
以下解决方案:125秒
y*w+x
我们的想法是创建一个批处理文件并执行它,利用“旧的好技术”。它的半蟒蛇但工作得更快。适用于Windows。
答案 7 :(得分:2)
outfile.write(infile.read()) 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) 0.60599684715271s
一个简单的基准测试显示shutil表现更好。
答案 8 :(得分:1)
如果文件不是巨大的:
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
如果文件太大而无法完全读取并保存在RAM中,则算法必须略有不同,例如使用read(10000)
读取每个要通过固定长度的块循环复制的文件。
答案 9 :(得分:1)
如果目录中有很多文件,那么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')
答案 10 :(得分:0)
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()
答案 11 :(得分:0)
这是Python 3的表示形式。
from pathlib import Path
filenames = ['file1.txt', 'file2.txt', ...]
output_file = Path('output_file.txt')
for file in file_list:
output_file.write_text(Path(file).read_text())
答案 12 :(得分:-2)
import os
files=os.listdir()
print(files)
print('#',tuple(files))
name=input('Enter the inclusive file name: ')
exten=input('Enter the type(extension): ')
filename=name+'.'+exten
output_file=open(filename,'w+')
for i in files:
print(i)
j=files.index(i)
f_j=open(i,'r')
print(f_j.read())
for x in f_j:
outfile.write(x)