我有一个包含20个文件名的列表,例如['file1.txt','file2.txt',...]
。我想编写一个Python脚本将这些文件连接成一个新文件。 我可以通过f = open(...)
打开每个文件,通过调用f.readline()
逐行读取,并将每行写入新文件中。但对我来说,这似乎不太“优雅”,特别是我必须逐行读写的那部分。
在Python中有更加“优雅”的方式吗?
我有一个包含20个文件名的列表,例如['file1.txt','file2.txt',...]
。我想编写一个Python脚本将这些文件连接成一个新文件。 我可以通过f = open(...)
打开每个文件,通过调用f.readline()
逐行读取,并将每行写入新文件中。但对我来说,这似乎不太“优雅”,特别是我必须逐行读写的那部分。
在Python中有更加“优雅”的方式吗?
这应该可以解决问题。
对于大文件:
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)
不幸的是,这种方法会留下一些未关闭的文件描述符,尽管这些应该由垃圾收集器自动处理。我只是觉得很有趣。
shutil.copyfileobj
答案会更快。 - flying sheep它会自动为您逐块读取输入文件,这更加高效,并且即使一些输入文件太大无法放入内存,也能正常工作:
import shutil
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)
这正是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
还有一些其他很棒的功能,比如通过过滤每一行来对文件进行原地修改的能力。
正如评论中所指出的,并在另一篇文章中讨论的那样,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()
for line in fileinput.input()
并不是最佳选择:OP想要连接文件,而不是逐行读取它们,这是一个理论上更长的执行过程。 - eyquemoutfile.write(infile.read()) # time: 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) # time: 0.60599684715271s
import glob
import os
for f in glob.glob("file*.txt"):
os.system("cat "+f+" >> OutFile.txt")
import os;
os.system("cat file*.txt >> OutFile.txt")
- libcat
可以接受一个文件列表,所以不需要重复调用它。你可以通过调用subprocess.check_call
而不是os.system
来轻松使其更安全。 - Clémentls | xargs cat | tee output.txt
可以完成任务(如果需要,你可以用subprocess从python中调用它)。cat * | tee output.txt
)。 - Clémentcat file1.txt file2.txt | tee output.txt
。 - GoTrained1> /dev/null
来禁用发送到 stdout(在终端中打印)的功能。 - GoTrainedglob2
生成文件名列表可能比手动编写更好。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')
glob2
而不是glob
模块或pathlib
中的通配符功能? - AMC以下是对@inspectorG4dget答案(截至2016年3月29日最佳答案)的替代方案。我测试了三个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()
这个想法是创建一个批处理文件并执行它,利用“老旧的好技术”。它是半Python,但速度更快。适用于Windows。
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])
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)
。os.open
和 os.read
,因为普通的 open
使用 Python 对 C 的 stdio 的包装器,这意味着会有1或2个额外的缓冲区妨碍您。 - abarnertoutf.write(line)
时,它不会重新写入磁盘块以只写入这80个字符; 这80个字符进入缓冲区,如果缓冲区现在超过8KB,则写入前8KB。 如果3MB比8KB更快,则会使用3MB缓冲区。 所以读取和写入3MB块之间唯一的区别在于您还需要进行一些RAM工作和字符串处理 - 这比磁盘快得多,因此通常并不重要。 - abarnert
cat file1.txt file2.txt file3.txt ... > output.txt
。在Python中,如果你不喜欢readline()
,总有readlines()
或者简单的read()
可供选择。 - jedwardssubprocess
模块运行cat file1.txt file2.txt file3.txt
命令,就完成了。但我不确定cat
在 Windows 上是否可用。 - Ashwini Chaudhary