Perl6: большие сжатые файлы читаются построчно - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь прочитать файл gz построчно в Perl6, однако меня блокируют:

  1. Как читать файл gz построчно вPerl6 однако, этот метод, считывающий все в :out, использует слишком много ОЗУ, чтобы использовать его, кроме очень маленьких файлов.

  2. Я не понимаю, как использовать Perl6Compress::Zlib чтобы получить все построчно, хотя я открыл вопрос об их github https://github.com/retupmoca/P6-Compress-Zlib/issues/17

  3. Я пытаюсь 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() ;

примерно так, используя Inline::Perl5 в Perl6:

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, если оно существует, я не могу его найти.

Как прочитать строку большого файлапострочно, не читая все в RAM в Perl6?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Обновление Сейчас протестировано, что выявило ошибку, теперь исправлено.

Решение # 2

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 и т. Д., Но понял это на основе:

  • Зная P6;

  • Чтение Compress::Zlib README и выбор подпрограммы zwrap;

  • Просмотр исходного кода модуля, в частности, подписи подпрограмма zwrap our sub 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.

Это привело меня к @ MattOates 'IO::Handle подобному объекту с .lines? Issue .Я не вижу ответа, и я не видел связанных репо на https://github.com/MattOates?tab=repositories.

0 голосов
/ 22 февраля 2019

Я сосредотачиваюсь на решении Inline::Perl5, которое вы попробовали.

Для вызова на $gz.gzreadline($_): похоже, что gzreadline пытаетсявернуть строку, прочитанную из 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;

Затем используйте 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 не передается по ссылке.

...