我试图在Perl6中逐行读取gz文件,但是,我被阻止了:
How to read gz file line by line in Perl6,但是,这种方法将所有内容读入:out
会占用过多的RAM,无法使用,除非是很小的文件。
我不了解如何使用Perl6的Compress::Zlib
逐行获取所有内容,尽管我在他们的github https://github.com/retupmoca/P6-Compress-Zlib/issues/17
我正在尝试Perl5的Compress::Zlib
来翻译此代码,该代码在Perl5中非常有效:
use Compress::Zlib; my $file = "data.txt.gz"; my $gz = gzopen($file, "rb") or die "Error reading $file: $gzerrno"; while ($gz->gzreadline($_) > 0) { # Process the line read in $_ } die "Error reading $file: $gzerrno" if $gzerrno != Z_STREAM_END ; $gz->gzclose() ;
在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();
但是我看不到如何翻译:(
我对Lib :: Archive示例https://github.com/frithnanth/perl6-Archive-Libarchive/blob/master/examples/readfile.p6感到困惑,在这里我看不到如何获得第3项之类的东西
应该有类似
for $file.IO.lines(gz) -> $line {
或Perl6中的类似内容(如果存在),我找不到它。
如何在不将所有内容都读入Perl6的RAM的情况下逐行读取大文件?
答案 0 :(得分:7)
更新现在已测试,发现了一个错误,现已修复。
use Compress::Zlib;
my $file = "data.txt.gz" ;
my $handle = try open $file or die "Error reading $file: $!" ;
my $zwrap = zwrap($handle, :gzip) ;
for $zwrap.lines {
.print
}
CATCH { default { die "Error reading $file: $_" } }
$handle.close ;
我已经用一个小的gzip压缩文本文件对此进行了测试。
我对gzip等不是很了解,但是基于以下原因发现了这一点:
知道P6;
阅读Compress::Zlib
's README
并选择zwrap
例程;
查看模块的源代码,尤其是the zwrap
routine our sub zwrap ($thing, :$zlib, :$deflate, :$gzip)
的签名;
反复试验,主要是为了猜测我需要传递:gzip
副词。
请评论我的代码是否对您有用。我猜最主要的是它对您拥有的大文件是否足够快。
在解决方案#2正常工作的情况下,我希望能够编写:
use Compress::Zlib ;
.print for "data.txt.gz".&zwrap(:gzip).lines ;
但是失败了:
No such method 'eof' for invocant of type 'IO::Path'
大概是因为此模块是在IO
类的重组之前编写的。
那导致我进入@MattOates' IO::Handle
like object with .lines
? issue。我注意到没有任何回应,也没有在https://github.com/MattOates?tab=repositories上看到相关的回购。
答案 1 :(得分:5)
我专注于您尝试过的Inline::Perl5
解决方案。
对于$gz.gzreadline($_)
的调用:gzreadline
似乎试图返回从zip文件by modifying its input argument $_
中读取的行(被视为输出参数,但这不是真正的Perl 5参考变量 [1] ),但修改后的值不会返回到Perl 6脚本中。
这是一个可能的解决方法: 在curent目录中创建包装器模块,例如 ./ 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;
然后在此包装器模块上使用Inline::Perl5
而不是Compress::Zlib
。例如 ./ p.p6 :
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();
[1]
在Perl 5中,您可以修改不是引用的输入参数,并且更改将反映在调用方中。这是通过修改特殊@_
数组变量中的条目来完成的。例如:sub quote { $_[0] = "'$_[0]'" } $str = "Hello"; quote($str)
将引用$str
,即使未通过引用传递$str
。