簡體   English   中英

Python相當於管道zcat結果到Perl中的文件句柄

[英]Python equivalent of piping zcat result to filehandle in Perl

我有一個用Python編寫的巨大管道,它使用非常大的.gz文件(約14GB壓縮),但需要更好的方法將某些行發送到外部軟件( 來自blast-legacy / 2.2.26的formatdb )。 我有很長一段時間以前為我寫過的Perl腳本這樣做非常快,但我需要在Python中做同樣的事情,因為管道的其余部分是用Python編寫的,我必須保持這種方式。 Perl腳本使用兩個文件句柄,一個用於保存.gz文件的zcat,另一個用於存儲軟件所需的行(每4個中有2個)並將其用作輸入。 它涉及生物信息學,但不需要經驗。 該文件采用fastq格式,軟件需要采用fasta格式。 每4行是一個fastq記錄,取第1行和第3行並將'>'添加到第1行的開頭,這就是formatdb軟件將用於每個記錄的fasta等價物。

perl腳本如下:

#!/usr/bin/perl 
my $SRG = $ARGV[0]; # reads.fastq.gz

open($fh, sprintf("zcat %s |", $SRG)) or die "Broken gunzip $!\n";

# -i: input -n: db name -p: program 
open ($fh2, "| formatdb -i stdin -n $SRG -p F") or die "no piping formatdb!, $!\n";

#Fastq => Fasta sub
my $localcounter = 0;
while (my $line = <$fh>){
        if ($. % 4==1){
                print $fh2 "\>" . substr($line, 1);
                $localcounter++;
        }
        elsif ($localcounter == 1){
                print $fh2 "$line";
                $localcounter = 0;
        }
        else{
        }
}
close $fh;
close $fh2;
exit;

它工作得很好。 我怎么能在Python中做同樣的事情? 我喜歡Perl如何使用這些文件句柄,但我不確定如何在不創建實際文件的情況下在Python中執行此操作。 我能想到的只是gzip.open文件並將我需要的每條記錄的兩行寫入一個新文件並將其與“formatdb”一起使用,但它太慢了。 有任何想法嗎? 我需要將它工作到python管道中,所以我不能只依賴於perl腳本,而且我也想知道如何一般地執行此操作。 我假設我需要使用某種形式的子進程模塊。

這是我的Python代碼,但同樣是慢速和速度是這里的問題(巨大的文件):

#!/usr/bin/env python

import gzip
from Bio import SeqIO # can recognize fasta/fastq records
import subprocess as sp
import os,sys

filename = sys.argv[1] # reads.fastq.gz

tempFile = filename + ".temp.fasta"

outFile = open(tempFile, "w")

handle = gzip.open(filename, "r")
# parses each fastq record
# r.id and r.seq are the 1st and 3rd lines of each record
for r in SeqIO.parse(handle, "fastq"):
    outFile.write(">" + str(r.id) + "\n")
    outFile.write(str(r.seq) + "\n")

handle.close()
outFile.close()

    cmd = 'formatdb -i ' + str(tempFile) + ' -n ' + filename + ' -p F '
    sp.call(cmd, shell=True)

    cmd = 'rm ' + tempFile
    sp.call(cmd, shell=True)

首先,在Perl和Python中都有一個更好的解決方案:只需使用一個gzip庫。 在Python中, stdlib中有一個; 在Perl中,您可以在CPAN上找到一個。 例如:

with gzip.open(path, 'r', encoding='utf-8') as f:
    for line in f:
        do_stuff(line)

zcat更簡單,更高效,更便攜。


但是,如果您確實想要在Python中啟動子流程並控制其管道,則可以使用subprocess模塊執行此操作。 而且,與perl不同,Python可以做到這一點,而不必在中間粘貼一個shell。 使用subprocess模塊替換舊函數的文檔中甚至還有一個很好的部分,它為您提供了配方。

所以:

zcat = subprocess.Popen(['zcat', path], stdout=subprocess.PIPE)

現在, zcat.stdout是一個類文件對象,使用常用的read方法等,將管道包裝到zcatzcat

因此,例如,在Python 3.x中一次讀取一個二進制文件8K:

zcat = subprocess.Popen(['zcat', path], stdout=subprocess.PIPE)
for chunk in iter(functools.partial(zcat.stdout.read, 8192), b''):
    do_stuff(chunk)
zcat.wait()

(如果你想在Python 2.x中執行此操作,或者一次讀取一行文本文件而不是一次讀取8K二進制文件,或者其他任何內容,則更改與其他任何文件的更改相同 - 處理編碼。)

您可以使用此函數解析整個文件並將其作為行列表加載:

    def convert_gz_to_list_of_lines(filepath):
     """Parse gz file and convert it into a list of lines."""
     file_as_list = list()
     with gzip.open(filepath, 'rt', encoding='utf-8') as f:
      try:
       for line in f:
        file_as_list.append(line)
      except EOFError:
        file_as_list = file_as_list
      return file_as_list

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM