Perl6:逐行读取大型gzip文件
我试图在Perl6中逐行读取gz文件,但是,我被阻止了: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>;
:out
的方法使用了太多的RAM,除了在非常小的文件上之外,都无法使用Compress::Zlib
逐行获取所有内容,尽管我在他们的github上发现了一个问题Compress::Zlib
来翻译这段代码,它在Perl5中非常有效: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();
但我看不出该如何翻译:(
对于$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 5gReadLine
函数的更多信息:在Perl 5中,您可以修改不是引用的输入参数,更改将反映在调用者中。这是通过修改特殊的@
数组变量中的条目来完成的。例如:子引号{$\u0]=“$\u[0]”“}$str=“Hello”;quote($str)
将引用$str
,即使$str
不是通过引用传递的。我不确定Inline::Perl5
是否可以处理此类输出参数参考项4,只是为了澄清:底层库提供了一个存档读取数据块()
这是一种通用方法,必须适用于每种归档格式的每种文件。读取文件内容
方法以Buf
返回整个文件。要逐行读取文件,应该使用归档::Libarchive::Raw
编写自己的方法,但我发现有更简单的方法,如图a所示回答你的问题。你可以使用lib:from';
来更改Perl5使用的路径。然后使用MyZlibWrapper:from;
就可以了。