Python 处理多个文件时的快速I/O
我有两个输入文件,我想混合它们并将结果输出到第三个文件中。在下面,我将使用一个玩具示例来解释文件的格式和所需的输出。每个文件都包含重复的4行模式(但包含不同的序列),我只包含单个4行: 输入文件1:Python 处理多个文件时的快速I/O,python,linux,bash,performance,io,Python,Linux,Bash,Performance,Io,我有两个输入文件,我想混合它们并将结果输出到第三个文件中。在下面,我将使用一个玩具示例来解释文件的格式和所需的输出。每个文件都包含重复的4行模式(但包含不同的序列),我只包含单个4行: 输入文件1: @readheader1 ACACACACACACACACACACACACACACACACACACACACACACACACACACAC + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ... 输入文件2: @readheader2
@readheader1
ACACACACACACACACACACACACACACACACACACACACACACACACACACAC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
...
输入文件2:
@readheader2
AATTAATT
+
FFFFFFFF
...
所需输出:
@readheader1_AATTAATT
ACACACACACACACACACACACACACACACACACACACACACACACACACACAC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
...
因此,我想使用下划线将第一个文件中每四行的第一行附加到第二个文件中每四行的第二行中的小序列。我只需将第一行的每四行中的第2n行、第3行和第4行按原样输出到输出中
我正在寻找任何脚本(Linux BASH,Python,C++等),可以优化我下面的内容:
我写了这段代码来完成这项任务,但我发现速度很慢(60 GB和15 GB大小的输入需要一天以上的时间);请注意,输入文件采用fastq.gz
格式,因此我使用gzip打开它们:
...
r1_file = gzip.open(r1_file_name, 'r') # input file 1
i1_file = gzip.open(i1_file_name, 'r') # input file 2
out_file_R1 = gzip.open('_R1_barcoded.fastq.gz', 'wb') # output file
r1_header = ''
r1_seq = ''
r1_orient = ''
r1_qual = ''
i1_seq = ''
cnt = 1
with gzip.open(r1_file_name, 'r') as r1_file:
for r1_line in r1_file:
if cnt==1:
r1_header = str.encode(r1_line.decode("ascii").split(" ")[0])
next(i1_file)
if cnt==2:
r1_seq = r1_line
i1_seq = next(i1_file)
if cnt==3:
r1_orient = r1_line
next(i1_file)
if cnt==4:
r1_qual = r1_line
next(i1_file)
out_4line = r1_header + b'_' + i1_seq + r1_seq + r1_orient + r1_qual
out_file_R1.write(out_4line)
cnt = 0
cnt += 1
i1_file.close()
out_file_R1.close()
然后,我使用2个数据集进行了两个输出,我希望交错输出文件:第一个文件的4行、第二个文件的4行、第一个文件的4行,依此类推……使用paste
实用程序(来自GNU coreutils)和GNUsed
:
paste file1 file2 |
sed -E 'N; s/\t.*\n([^\t]*)\t(.*)/_\2\n\1/; N; N; s/\t[^\n]*//g' > file.out
如果文件是gzip文件,则使用:
paste <(gzip -dc file1.gz) <(gzip -dc file2.gz) |
sed -E 'N; s/\t.*\n([^\t]*)\t(.*)/_\2\n\1/; N; N; s/\t[^\n]*//g' > file.out
文件2:
Header2
AATTAATT
YY
GGGGGG
在执行粘贴
命令后,行被合并,由选项卡
s分隔:
Header1\tHeader2
ACACACACAC\tAATTAATT
XX\tYY
FFFFFFFFFFFF\tGGGGGG
上面的\t
表示制表符。这些行被送入sed
sed
读取第一行,模式空间变为
Header1\tHeader2
Header1\tHeader2\nACACACACAC\tAATTAATT
Header1_AATTAATT\nACACACACAC
N
命令向模式空间添加一个换行符,然后将输入的下一行(acacac\taattatt
)追加到模式空间。模式空间变为
Header1\tHeader2
Header1\tHeader2\nACACACACAC\tAATTAATT
Header1_AATTAATT\nACACACACAC
并与regex\t.*\n([^\t]*)\t(.*)
匹配,如下所示
Header1\tHeader2\nACACACACAC\tAATTAATT
||^^^^^^^||^^^^^^^^^^||^^^^^^^^
\t .* \n ([^\t]*) \t (.*)
|| || \1 || \2
\n
表示换行符。然后用s/\t.*\n([^\t]*)\t(.*)/\u2\n\1/
命令将匹配部分替换为\u2\n\1
。模式空间变为
Header1\tHeader2
Header1\tHeader2\nACACACACAC\tAATTAATT
Header1_AATTAATT\nACACACACAC
两个N
命令读取下面两行。现在模式空间是
Header1_AATTAATT\nACACACACAC\nXX\tYY\nFFFFFFFFFFFF\tGGGGGG
Header1_AATTAATT\nACACACACAC\nXX\nFFFFFFFFFFFF
s/\t[^\n]*//g
命令删除选项卡(包含)和换行符(独占)之间的所有部分。完成此操作后,最终的图案空间为
Header1_AATTAATT\nACACACACAC\nXX\tYY\nFFFFFFFFFFFF\tGGGGGG
Header1_AATTAATT\nACACACACAC\nXX\nFFFFFFFFFFFF
打印为
Header1_AATTAATT
ACACACACAC
XX
FFFFFFFFFFFF
您可能希望研究使用asyncio()将代码拆分为协同路由。考虑到您的用例,它可能是最有效的工具。线程是您可以尝试的另一个选项,尽管如果您使用线程进行如此多的I/O,会浪费相当多的CPU时间。您可能还希望在处理之前解压缩文件。非常感谢;你能解释一下它是如何工作的吗?比如如何使用regex命令访问每条记录?@ameerosein补充了一个解释。