2016-12-08 2 views
2

В bash вы можете объединить gzip-файлы, и результат будет действительным gzip-файлом. Насколько я помню, я всегда был в состоянии рассматривать эти «каскадные» сжат GZIP файлы как обычные сжат GZIP файлы (мой пример кода из ссылки выше):IO :: Uncompress :: Gunzip останавливается после первого «оригинального» gzipped-файла внутри «конкатенированного» gzipped-файла

echo 'Hello world!' > hello.txt 
echo 'Howdy world!' > howdy.txt 
gzip hello.txt 
gzip howdy.txt 

cat hello.txt.gz howdy.txt.gz > greetings.txt.gz 

gunzip greetings.txt.gz 

cat greetings.txt 

Какие выходы

Hello world! 
Howdy world! 

Однако, при попытке прочитать этот же файл с помощью Perl's core IO::Uncompress::Gunzip module, он не проходит мимо первого исходного файла. Вот результат:

./my_zcat greetings.txt.gz 
Hello world! 

Вот код для my_zcat:

#!/bin/env perl 
use strict; 
use warnings; 
use v5.10; 

use IO::Uncompress::Gunzip qw($GunzipError); 

my $file_name = shift; 

my $fh = IO::Uncompress::Gunzip->new($file_name) or die $GunzipError; 

while (defined(my $line = readline $fh)) 
{ 
    print $line; 
} 

Если я полностью распаковывать файлы перед созданием нового файла сжатого, у меня нет этой проблемы:

zcat hello.txt.gz howdy.txt.gz | gzip > greetings_via_zcat.txt.gz 
./my_zcat greetings_via_zcat.txt.gz 
Hello world! 
Howdy world! 

Итак, в чем разница между greetings.txt.gz и greetings_via_zcat.txt.gz и почему может IO::Uncompress::Gunzip правильно работать с greetings.txt.gz ?

Основываясь на этом answer to another question, я предполагаю, что IO::Uncompress::Gunzip испортится из-за метаданных между файлами. Но, поскольку greetings.txt.gz является допустимым файлом Gzip, я бы ожидал, что IO::Uncompress::Gunzip будет работать.

Мой обходной путь сейчас будет обжигающе от zcat (который, конечно, не помогает пользователям Windows, много):

#!/bin/env perl 
use strict; 
use warnings; 
use v5.10; 

my $file_name = shift; 

open(my $fh, '-|', "zcat $file_name"); 

while (defined(my $line = readline $fh)) 
{ 
    print $line; 
} 
+1

Для справки, этот вопрос также был размещен на трекер ошибок модуля: https://rt.cpan.org /Public/Bug/Display.html?id=119184 – melpomene

+0

@melpomene Спасибо. Ты подтолкнул меня на это. –

+0

@melpomene Билет отмечен как разрешенный, поскольку он задокументирован в [IO :: Compress] (https://metacpan.org/pod/distribution/IO-Compress/lib/IO/Compress/FAQ.pod#Dealing-with-concatenated -gzip-files), чтобы использовать параметр MultiStream для решения этой проблемы. –

ответ

3

Это описано в явном виде в разделе IO :: Компресс FAQ Dealing with concatenated gzip files. В основном вам нужно включить параметр MultiStream, когда вы создаете объект IO :: Uncompress :: Gunzip.

Вот definition of the MultiStream option:

MultiStream => 0|1

Если входной файл/буфер содержит множественный сжатых потоков данных, эта опция будет распаковывать всю партию, как единый поток данных.

По умолчанию 0.

Так что ваш код должен это изменение

my $fh = IO::Uncompress::Gunzip->new($file_name, MultiStream => 1) or die $GunzipError; 
+0

Это прекрасно.Я сейчас громко смеюсь, потому что помню, как я искал «IO :: Uncompress :: Gunzip» и пропускал обращения к документации «IO :: Compress», потому что это был «другой» модуль. –

Смежные вопросы