![](/img/trans.png)
[英]Is there are Python equivalent of Perl's __DATA__ filehandle?
[英]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
方法等,將管道包裝到zcat
子zcat
。
因此,例如,在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.