处理多个文件时快速 I/O

Fast I/O when working with multiple files

我有两个输入文件,我想将它们混合并将结果输出到第三个文件中。在下文中,我将使用玩具示例来解释文件的格式和所需的输出。每个文件包含重复的 4 行模式(但包含不同的序列),我只包含单个 4 行:

输入文件1:

@readheader1
ACACACACACACACACACACACACACACACACACACACACACACACACACACAC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
...

输入文件2:

@readheader2
AATTAATT
+
FFFFFFFF
...

期望的输出:

@readheader1_AATTAATT
ACACACACACACACACACACACACACACACACACACACACACACACACACACAC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
...

所以我想在 small sequence found in the second line of every four line from the second file 上使用下划线附加 first line of every four line from the first file。我只是将第一行的每四行中的第 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)和 GNU sed:

paste file1 file2 |
sed -E 'N; s/\t.*\n([^\t]*)\t(.*)/_\n/; 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(.*)/_\n/; N; N; s/\t[^\n]*//g' > file.out

注意:这假设文件 1 和文件 2 中没有制表符


解释: 假设 file1 和 file2 包含这些行:
文件 1:

Header1
ACACACACAC
XX
FFFFFFFFFFFF

文件 2:

Header2
AATTAATT
YY
GGGGGG

paste命令之后,行被合并,由TABs分隔:

Header1\tHeader2
ACACACACAC\tAATTAATT
XX\tYY
FFFFFFFFFFFF\tGGGGGG

上面的\t表示制表符。这些行被馈送到 sedsed 读取第一行,模式 space 变为

Header1\tHeader2

N 命令向模式 space 添加一个换行符,然后将输入的下一行 (ACACACACAC\tAATTAATT) 附加到模式 space。模式 space 变为

Header1\tHeader2\nACACACACAC\tAATTAATT

并与正则表达式 \t.*\n([^\t]*)\t(.*) 匹配,如下所示。

Header1\tHeader2\nACACACACAC\tAATTAATT
       ||^^^^^^^||^^^^^^^^^^||^^^^^^^^
       \t   .*  \n ([^\t]*) \t  (.*)
       ||       ||        ||   
      

\n表示一个换行符。然后通过s/\t.*\n([^\t]*)\t(.*)/_\n/命令将匹配的部分替换为_\n。模式 space 变为

Header1_AATTAATT\nACACACACAC

两个N命令读取接下来的两行。现在模式 space 是

Header1_AATTAATT\nACACACACAC\nXX\tYY\nFFFFFFFFFFFF\tGGGGGG

s/\t[^\n]*//g 命令删除 TAB(含)和换行符(不含)之间的 所有 部分。此操作后最终模式 space 是

Header1_AATTAATT\nACACACACAC\nXX\nFFFFFFFFFFFF

打印为

Header1_AATTAATT
ACACACACAC
XX
FFFFFFFFFFFF