Perl6:逐行读取大型gzip文件

Perl6:逐行读取大型gzip文件,gzip,raku,Gzip,Raku,我试图在Perl6中逐行读取gz文件,但是,我被阻止了: 然而,这种将所有内容读入:out的方法使用了太多的RAM,除了在非常小的文件上之外,都无法使用 我不知道如何使用Perl6的Compress::Zlib逐行获取所有内容,尽管我在他们的github上发现了一个问题 我正在尝试Perl5的Compress::Zlib来翻译这段代码,它在Perl5中非常有效: 使用Perl6中的Inline::Perl5执行类似操作: use Compress::Zlib:from<Perl5>;

我试图在Perl6中逐行读取gz文件,但是,我被阻止了:

  • 然而,这种将所有内容读入
    :out
    的方法使用了太多的RAM,除了在非常小的文件上之外,都无法使用

  • 我不知道如何使用Perl6的
    Compress::Zlib
    逐行获取所有内容,尽管我在他们的github上发现了一个问题

  • 我正在尝试Perl5的
    Compress::Zlib
    来翻译这段代码,它在Perl5中非常有效:

  • 使用Perl6中的
    Inline::Perl5
    执行类似操作:

    use Compress::Zlib:from<Perl5>;
    my $file = 'chrMT.1.vcf.gz';
    my $gz = Compress::Zlib::new(gzopen($file, 'r');
    while ($gz.gzreadline($_) > 0) {
      print $_;
    }
    $gz.gzclose();
    
    使用Compress::Zlib:from;
    my$file='chrMT.1.vcf.gz';
    my$gz=Compress::Zlib::new(gzopen($file,'r');
    而($gz.gzreadline($)>0){
    打印美元;
    }
    $gz.gzclose();
    
    但我看不出该如何翻译:(

  • 我被Lib::Archive示例弄糊涂了,我不知道如何在这里获得类似于第3项的内容

  • 应该是这样的

  • 对于$file.IO.lines(gz)->$line{
    或类似于Perl6中的代码,如果它存在,我找不到它

    如何在Perl6中逐行读取一个大文件而不将所有内容都读入RAM?

    我正在关注您尝试的解决方案

    对于调用
    $gz.gzreadline($\uz)
    :它似乎试图返回从zip文件读取的行(被视为输出参数,但它不是真正的Perl 5引用变量[1]),但修改后的值不会返回到Perl 6脚本

    以下是一个可能的解决方法: 在当前目录中创建包装器模块,例如/MyZlibWrapper.pm

    package MyZlibWrapper;
    use strict;
    use warnings;
    use Compress::Zlib ();
    use Exporter qw(import);
    
    our @EXPORT = qw(gzopen);
    our $VERSION = 0.01;
    
    sub gzopen {
        my ( $fn, $mode ) = @_;
        my $gz = Compress::Zlib::gzopen( $fn, $mode );
        my $self = {gz => $gz}; 
        return bless $self, __PACKAGE__;
    }
    
    sub gzreadline {
        my ( $self ) = @_;
        my $line = "";
        my $res = $self->{gz}->gzreadline($line);
        return [$res, $line];
    }
    
    sub gzclose {
        my ( $self ) = @_;
        $self->{gz}->gzclose();
    }    
    
    1;
    
    use v6;
    use lib:from<Perl5> '.';
    use MyZlibWrapper:from<Perl5>;
    my $file = 'data.txt.gz';
    my $mode = 'rb';
    my $gz = gzopen($file, $mode);
    loop {
        my ($res, $line) = $gz.gzreadline();
        last if $res == 0;
        print $line;
    }
    $gz.gzclose();
    
    然后在此包装器模块上使用
    Inline::Perl5
    ,而不是
    Compress::Zlib
    。例如/p.p6

    package MyZlibWrapper;
    use strict;
    use warnings;
    use Compress::Zlib ();
    use Exporter qw(import);
    
    our @EXPORT = qw(gzopen);
    our $VERSION = 0.01;
    
    sub gzopen {
        my ( $fn, $mode ) = @_;
        my $gz = Compress::Zlib::gzopen( $fn, $mode );
        my $self = {gz => $gz}; 
        return bless $self, __PACKAGE__;
    }
    
    sub gzreadline {
        my ( $self ) = @_;
        my $line = "";
        my $res = $self->{gz}->gzreadline($line);
        return [$res, $line];
    }
    
    sub gzclose {
        my ( $self ) = @_;
        $self->{gz}->gzclose();
    }    
    
    1;
    
    use v6;
    use lib:from<Perl5> '.';
    use MyZlibWrapper:from<Perl5>;
    my $file = 'data.txt.gz';
    my $mode = 'rb';
    my $gz = gzopen($file, $mode);
    loop {
        my ($res, $line) = $gz.gzreadline();
        last if $res == 0;
        print $line;
    }
    $gz.gzclose();
    
    使用v6;
    使用lib:from';
    使用MyZlibWrapper:from;
    my$file='data.txt.gz';
    my$mode='rb';
    my$gz=gzopen($file$mode);
    环路{
    my($res,$line)=$gz.gzreadline();
    如果$res==0,则为最后一个;
    打印$行;
    }
    $gz.gzclose();
    
    [1] 在Perl 5中,您可以修改不是引用的输入参数,更改将反映在调用者中。这是通过修改特殊的
    @
    数组变量中的条目来完成的。例如:
    sub quote{$\[0]=“$\[0]'”}$str=“Hello”quote($str)
    将引用
    $str
    ,即使
    $str
    未通过引用传递。

    更新现已测试,发现错误,现已修复

    解决方案#2 我已经用一个小的gzip文本文件测试过了

    我对gzip等不太了解,但我是根据以下情况得出结论的:

    • 了解P6

    • 读取并选择
      zwrap
      例程

    • 查看模块的源代码,特别是
      我们的子zwrap($thing,:$zlib,:$deflate,:$gzip)的签名

    • 还有反复试验,主要是猜测我需要通过
      :gzip
      副词


    请评论我的代码是否适用于您。我猜主要的问题是它是否足够快,适合您拥有的大文件

    解决方案5的尝试失败 有了解决方案#2,我本来希望能够写下:

    use Compress::Zlib ;
    .print for "data.txt.gz".&zwrap(:gzip).lines ;
    
    但这在以下方面是行不通的:

    No such method 'eof' for invocant of type 'IO::Path'
    
    这大概是因为该模块是在重组
    IO
    类之前编写的


    这让我想到了。我没有注意到任何响应,也没有看到相关的repo。

    Re:“using Inline::Perl5”:对于调用
    $gz.gzreadline($)
    :似乎
    gzreadline
    试图通过修改输入参数
    $\uz>来返回从zip文件读取的行(视为输出参数,但不是真正的Perl 5引用变量),但该值不会返回到Perl 6脚本。有关Perl 5
    gReadLine
    函数的更多信息:在Perl 5中,您可以修改不是引用的输入参数,更改将反映在调用者中。这是通过修改特殊的
    @
    数组变量中的条目来完成的。例如:
    子引号{$\u0]=“$\u[0]”“}$str=“Hello”;quote($str)
    将引用
    $str
    ,即使
    $str
    不是通过引用传递的。我不确定
    Inline::Perl5
    是否可以处理此类输出参数参考项4,只是为了澄清:底层库提供了一个
    存档读取数据块()
    这是一种通用方法,必须适用于每种归档格式的每种文件。
    读取文件内容
    方法以
    Buf
    返回整个文件。要逐行读取文件,应该使用
    归档::Libarchive::Raw
    编写自己的方法,但我发现有更简单的方法,如图a所示回答你的问题。你可以
    使用lib:from';
    来更改Perl5使用的路径。然后
    使用MyZlibWrapper:from;
    就可以了。