2015-01-14 3 views
0

Я пытаюсь понять, как использовать IO :: Uncompress :: Unzip, чтобы распаковать Jar-файлы. У меня есть имена файлов в печати банки, но я получаю сообщение об ошибке:Perl IO :: Uncompress :: Unzip

Can't call method "reset" on an undefined value at ../IO/Uncompress/Base.pm line 986. 

после того как я прочитал последнюю запись. Вот мой модуль:

sub modify_artifact { 
    my %parameters = @_; 

    my @required_parameters = qw(version directory); 

    for my $parameter (@required_parameters) { 
     if (not exists $parameters{$parameter}) { 
      die qq(ERROR: Missing required parameter "$parameter"); 
     } 
    } 
    my $directory = $parameters{directory}; 

    my $dir_fh = IO::Dir->new($parameters{directory}) or 
     die qq(ERROR: Cannot open directory "$parameters{directory} for reading.); 

    while (my $file_name = $dir_fh->read) { 
     next if $file_name =~ /^\./;    #Hidden and "." and ".." 
     my $full_file_name = File::Spec->join($directory, $file_name); 
     my $archive_fh = IO::Uncompress::Unzip->new($full_file_name) or 
      die qq(ERROR: Cannot open file "$full_file_name" for reading.); 
     while (my $status = $archive_fh->nextStream) { 
      last unless $status > 0; 
      say $archive_fh->getHeaderInfo->{Name}; # Print out file or directory 
     } 
    } 

} 

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

META-INF/MANIFEST.MF 
META-INF/maven/ 
META-INF/maven/com.vegicorp/ 
META-INF/maven/com.vegicorp/services/ 
META-INF/maven/com.vegicorp/services/pom.properties 
META-INF/maven/com.vegicorp/services/pom.xml 
com/ 
com/vegicorp/ 
com/vegicorp/services/ 
com/vegicorp/services/filter/ 
com/vegicorp/services/filter/impl/ 
com/vegicorp/services/generators/ 
com/vegicorp/services/filter/impl/DescInfoFilter.class 
com/vegicorp/services/filter/impl/RequestFilterAals.class 
com/vegicorp/services/generators/OutputGenerator$1.class 
com/vegicorp/services/generators/OutputGenerator.class <- Last entry in archive 
Can't call method "reset" on an undefined value at ../IO/Uncompress/Base.pm line 986. 

Я попробовал петлю for, показанную в тоже примерах:

sub modify_artifact { 
    my %parameters = @_; 

    my @required_parameters = qw(version directory); 

    for my $parameter (@required_parameters) { 
     if (not exists $parameters{$parameter}) { 
      die qq(ERROR: Missing required parameter "$parameter"); 
     } 
    } 
    my $directory = $parameters{directory}; 

    my $dir_fh = IO::Dir->new($parameters{directory}) or 
     die qq(ERROR: Cannot open directory "$parameters{directory} for reading.); 

    while (my $file_name = $dir_fh->read) { 
     next if $file_name =~ /^\./;    #Hidden and "." and ".." 
     my $full_file_name = File::Spec->join($directory, $file_name); 
     my $archive_fh = IO::Uncompress::Unzip->new($full_file_name) or 
      die qq(ERROR: Cannot open file "$full_file_name" for reading.); 
     my $status; 
     for ($status = 1; $status > 0; $status = $archive_fh->nextStream()) { 
      say $archive_fh->getHeaderInfo->{Name}; 
      last if $status < 0; 
     } 
    } 

} 

Но я получаю тот же вопрос. Похоже, что метод nextStream вызывает ошибку. Здесь что-то не хватает? Есть ли способ увидеть, есть ли следующий поток, прежде чем я его извлечу?

+0

Вам нужно использовать IO :: Uncompress :: Unzip? Архив :: Zip и Archive :: Extract имеют гораздо более приятные интерфейсы. – Schwern

+0

Это может быть правдой, но 'IO :: Uncompress :: Unzip' поставляется с Perl, а остальные - дополнительными модулями, которые должны быть установлены с помощью CPAN. Я бы предпочел использовать стандартные модули, когда они доступны, поскольку я знаю, что они будут там независимо от того, на каком компьютере я нахожусь. –

+0

Просто попробовал эквивалент того, что вы делаете в случайном файле jar. Отлично. Какую версию IO :: Uncompress :: Unzip вы используете? – pmqs

ответ

0

Я нашел проблему.

В каждом каталоге есть два файла: один - это POM, а один - файл jar (zip). Моя внешняя петля $dir_fh->read проходит через каталог, она сначала подбирает банку, затем POM.

Первый раз, внутренний контур сначала получает файл jar, открывается его IO::Uncompress::Unzip. Внутренний цикл не имеет проблем и выходит, как ожидалось.

Внешний контур теперь получает файл POM и передает его на IO::Uncompress::Unzip. IO::Uncompress::Unzip->new возвращает нулевой статус - даже если это не zip-файл. Однако, $archive_fh->nextStream каркает, потому что нет следующего потока для извлечения.

Поскольку у меня нет никаких указаний на то, что новый файл был открыт, я никогда не обнаружил, что POM был открыт, и с помощью nextStream это заставило мою программу каркать.

Итак, IO::Uncompress:Unzip->new открывает несжатые файлы, как если бы они были zip-файлами, и возвращает допустимый дескриптор файла.

Читая Perldoc, я нашел это под параметры конструктора:

  • Transparent => 0|1
     
    If this option is set and the input file/buffer is not compressed data, the module will allow reading of it anyway. In addition, if the input file/buffer does contain compressed data and there is non-compressed data immediately following it, setting this option will make this module treat the whole file/buffer as a single data stream.
     
    This option defaults to 1.

Хорошо, по умолчанию, IO::Uncompress::Unzip открывается без почтового индекса файлы для чтения. Если я хочу закончить это поведение, мне нужно сделать это:

my $archive_fh = IO::Uncompress::Unzip->new( 
    $full_file_name, 
    Transparent => 0, 
) or die qq(ERROR: Cannot open file "$full_file_name" for reading.); 

Это не будет открывать свой POM как ZIP, а программа работает.

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