Python等价于将zcat结果管道化到P中的filehandle

2024-05-28 18:16:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个用Python编写的巨大管道,它使用非常大的.gz文件(压缩约14GB),但需要更好的方法将某些行发送到外部软件(formatdb from blast-legacy/2.2.26)。我有一个很久以前有人为我写的Perl脚本,它的速度非常快,但是我需要用Python来做同样的事情,因为管道的其余部分是用Python编写的,我必须保持这种方式。Perl脚本使用两个文件句柄,一个用于保存.gz文件的zcat,另一个用于存储软件所需的行(每4行中有2行)并将其用作输入。它涉及生物信息学,但不需要经验。文件为fastq格式,软件需要它为fasta格式。每4行是一个fastq记录,取第一行和第三行,在第一行的开头加上“>;”,这是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代码,但这是一种降低速度的方法,这里的问题是速度(巨大的文件):

^{pr2}$

Tags: 文件脚本软件管道my记录速度perl
2条回答

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

    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

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

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

比花时间去zcat要简单得多,效率更高,可移植性更强。在


但是如果您真的想用Python启动子进程并控制它的管道,那么可以使用^{}模块来实现。而且,与Perl不同,Python可以做到这一点而不必在中间插入一个shell。在Replacing Older Functions with the ^{} Module的文档中甚至有一个很好的部分给你食谱。在

所以:

^{pr2}$

现在,zcat.stdout是一个类似文件的对象,使用通常的read方法等,将管道包装到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()

(如果您想在Python2.x中执行此操作,或者一次读取一个文本文件,而不是一次读取一个二进制文件8K,或者其他任何方法,那么这些更改与任何其他处理文件编码的更改相同。)

相关问题 更多 >

    热门问题