首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Python等价物将zcat结果通过管道传送到Perl中的文件句柄

Python等价物将zcat结果通过管道传送到Perl中的文件句柄
EN

Stack Overflow用户
提问于 2015-05-05 20:17:30
回答 2查看 6.8K关注 0票数 7

我有一个用Python语言编写的巨大的管道,它使用非常大的.gz文件(大约14 an压缩),但需要一种更好的方法来将某些行发送到外部软件(formatdb from blast-legacy/2.2.26)。我有一个很久以前有人为我写的Perl脚本,它可以非常快地完成这项工作,但我需要在Python中做同样的事情,因为管道的其余部分都是用Python编写的,我必须保持这种方式。Perl脚本使用两个文件句柄,一个用于保存.gz文件的zcat,另一个用于存储软件所需的行(每4行中有2行)并将其用作输入。它涉及生物信息学,但不需要经验。该文件为fastq格式,软件需要fasta格式。每4行是一个fastq记录,取第一行和第三行,并在第一行的开头加上'>‘,这是formatdb软件将用于每条记录的fasta等价物。

perl脚本如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/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”来使用它,但是它太慢了。有什么想法吗?我需要把它放到python管道中,所以我不能仅仅依靠perl脚本,我还想知道一般情况下如何做到这一点。我假设我需要使用某种形式的子进程模块。

这是我的Python代码,但它仍然很慢,速度是这里的问题(大型文件):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/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)
EN

回答 2

Stack Overflow用户

发布于 2015-05-05 20:25:10

首先,在Perl和Python中都有一个更好的解决方案:只需使用gzip库。在Python中,有一个in the stdlib;在Perl语言中,您可以在CPAN上找到一个。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with gzip.open(path, 'r', encoding='utf-8') as f:
    for line in f:
        do_stuff(line)

zcat相比,这要简单得多,效率更高,可移植性也更好。

但是,如果您确实希望在Python中启动子进程并控制其管道,则可以使用subprocess模块来实现。而且,与perl不同的是,Python可以做到这一点,而不必在中间插入shell。甚至在Replacing Older Functions with the subprocess Module的文档中有一个很好的部分,可以为您提供食谱。

所以:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
zcat = subprocess.Popen(['zcat', path], stdout=subprocess.PIPE)

现在,zcat.stdout是一个类似文件的对象,它具有常用的read方法等,将管道包装到zcat子进程。

因此,例如,要在Python 3.x中一次读取一个8K的二进制文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的二进制文件,或者其他任何情况,这些更改与任何其他文件处理代码的更改都是相同的。)

票数 11
EN

Stack Overflow用户

发布于 2018-03-13 19:17:18

您可以使用以下函数解析整个文件并将其加载为一系列行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30062482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文