最有效的文件连接和重排方法
我正在处理几个文件,每个文件分成两部分,第一部分是几千行的头部,接下来是几千行的主体。我的问题是,我需要把这些文件合并成一个文件,要求所有的头部在最上面,下面是主体部分。
目前我使用了两个循环:一个循环用来提取所有的头部并写入文件,另一个循环用来写入每个文件的主体部分(我还使用了一个 tmp_count
变量来限制加载到内存中的行数,然后再写入文件)。
这样做速度比较慢——处理一个13GB的文件大约需要6分钟。有没有人能告诉我怎么优化这个过程,或者在Python中有没有更快的方法?
谢谢!
这是我的代码:
def cat_files_sam(final_file_name,work_directory_master,file_count):
final_file = open(final_file_name,"w")
if len(file_count) > 1:
file_count=sort_output_files(file_count)
# only for @ headers
for bowtie_file in file_count:
#print bowtie_file
tmp_list = []
tmp_count = 0
for line in open(os.path.join(work_directory_master,bowtie_file)):
if line.startswith("@"):
if tmp_count == 1000000:
final_file.writelines(tmp_list)
tmp_list = []
tmp_count = 0
tmp_list.append(line)
tmp_count += 1
else:
final_file.writelines(tmp_list)
break
for bowtie_file in file_count:
#print bowtie_file
tmp_list = []
tmp_count = 0
for line in open(os.path.join(work_directory_master,bowtie_file)):
if line.startswith("@"):
continue
if tmp_count == 1000000:
final_file.writelines(tmp_list)
tmp_list = []
tmp_count = 0
tmp_list.append(line)
tmp_count += 1
final_file.writelines(tmp_list)
final_file.close()
3 个回答
0
你想写的代码里有两个明显的低效之处(这里说的不是你展示的代码):
- 在第一个主要的
for
循环里,你在不断累积大量的头部行,而不是直接把它们写出来。 - 在第二个主要的
for
循环中,你又一行一行地跳过文件的头部,而在第一个循环里你已经确定了头部的结束位置。可以参考一下 file.seek 和 file.tell。
2
你觉得移动13Gb的数据需要多快呢?这个问题主要是跟输入输出(I/O)有关,而不是Python本身的问题。要让速度更快,就要减少输入输出的操作。这意味着你要么就只能接受现在的速度,要么就需要调整你工具链后面的部分,让它们直接处理文件,而不是一次性处理一个巨大的13Gb文件。
2
如果你有足够的磁盘空间,可以节省第二次跳过文件头的时间。除了最终要生成的文件外,还可以打开一个临时文件 temp_file
,并进行以下操作:
import shutil
hdr_list = []
bod_list = []
dispatch = {True: (hdr_list, final_file),
False: (bod_list, temp_file)}
for bowtie_file in file_count:
with open(os.path.join(work_directory_master,bowtie_file)) as f:
for line in f:
L, fou = dispatch[line[0]=='@']
L.append(f)
if len(L) == 1000000:
fou.writelines(L)
del L[:]
# write final parts, if any
for L, fou in dispatch.items():
if L: fou.writelines(L)
temp_file.seek(0)
shutil.copyfileobj(temp_file, final_file)
这样做可以提高你程序的运行效率。你可以考虑调整现在写死的 1000000
,或者干脆不使用列表,直接把每一行写入到合适的文件(最终文件或临时文件)中,这些都是值得测试的选项。不过,如果你的内存没有限制,那么这些调整可能影响不大——不过,关于性能的直觉往往会让人误解,所以最好还是实际测试一下效果!