使用IO::Uncompress::AnyUncompress读取zip文件的Perl

4
我们将从现有的构建系统(混乱不堪)转换为使用Ant和Ivy的构建系统。我正在清理所有构建文件,并查找jar依赖项。如果我可以通过查找项目中检入的jars,查找它们包含哪些类,然后将这些类与Java代码中的各种import语句匹配,那么我认为自动化处理会更容易一些。
我以前使用过Archive::Tar,但Archive::Zip不是标准的Perl模块。(我的担忧是,有人将尝试运行我的脚本,在半夜打电话告诉我它无法工作。)
我注意到IO::Uncompress::AnyUncompress是一个标准模块,所以我想尝试一下IO::Uncompress::AnyUncompress或者至少使用标准的模块IO::Uncompress::Unzip
不幸的是,这些模块的文档中没有示例(根据文档,示例是一个待办事项)。
我能够成功地打开我的jar并创建一个对象:
 my $zip_obj = IO::Uncompress::AnyUncompress->new ( $zip_file );

现在,我想查看内容。根据文档:

getHeaderInfo

用法如下:

$hdr  = $z->getHeaderInfo();
@hdrs = $z->getHeaderInfo();

这种方法返回一个哈希引用(在标量上下文中)或包含压缩数据流中每个头字段信息的列表或哈希引用(在数组上下文中)。
好的,这不像Archive::Tar或Archive::Zip返回的对象那样,并且没有提到用于解析数据的方法或子例程。我将使用Data::Dumper并查看参考中包含哪些哈希键。
以下是一个简单的测试程序:
#! /usr/bin/env perl
use 5.12.0;
use warnings;

use IO::Uncompress::AnyUncompress;
use Data::Dumper;

my $obj = IO::Uncompress::AnyUncompress->new("testng.jar")

    or die qq(You're an utter failure);

say qq(Dump of \$obj = ) . Dumper $obj;

my @header2 = $obj->getHeaderInfo;
say qq(Dump of \$header = ) . Dumper $headers->[0];

以下是我的结果:
Dump of $obj = $VAR1 = bless( \*Symbol::GEN0, 'IO::Uncompress::Unzip' );

Dump of $header = $VAR1 = {
          'UncompressedLength' => 0,
          'Zip64' => 0,
          'MethodName' => 'Stored',
          'Stream' => 0,
          'Time' => 1181224440,
          'MethodID' => 0,
          'CRC32' => 0,
          'HeaderLength' => 43,
          'ExtraFieldRaw' => '¦-  ',
          'ExtraField' => [
                            [
                              '¦-',
                              ''
                            ]
                          ],
          'FingerprintLength' => 4,
          'Type' => 'zip',
          'TrailerLength' => 0,
          'CompressedLength' => 0,
          'Name' => 'META-INF/',
          'Header' => 'PK
     +N¦6                 META-INF/¦-  '
        };

有些看起来很有用。但是,我的所有条目都返回“'Name' => 'META-INF/`”,所以它看起来不像是文件名。

是否可以使用IO::Uncompress::AnyUncompress(甚至IO::Uncompress:Unzip)来读取归档并查看其内容中的文件。如果可以,我该如何解析该标头?

否则,我将使用Archive::Zip,并让人们知道他们必须从CPAN下载并安装它到他们的系统中。

1个回答

4

存档文件中的数据流被压缩,因此您需要遍历数据流来获取各个文件。

use strict;
use warnings;
use IO::Uncompress::Unzip qw(unzip $UnzipError);

my $zipfile = 'zipfile.zip';
my $u = new IO::Uncompress::Unzip $zipfile
    or die "Cannot open $zipfile: $UnzipError";

die "Zipfile has no members"
    if ! defined $u->getHeaderInfo;

for (my $status = 1; $status > 0; $status = $u->nextStream) {
    my $name = $u->getHeaderInfo->{Name};
    warn "Processing member $name\n" ;

    if ($name =~ /\/$/) {
        mkdir $name;
    }
    else {
        unzip $zipfile => $name, Name => $name
            or die "unzip failed: $UnzipError\n";
    }
}

这个可以运行。我发现nextStream在工作时可能会返回1,当没有更多的流时返回0,当出现错误时返回-1,这就解释了为什么你使用了一个三部分的for语句而不是一个while循环。 - David W.
这并不是完全正确的,主要是因为末尾的 unzip 只是提取了存档文件。但是,您可以在此处使用 $u 作为文件句柄,例如 $u->read(),甚至将其移交给其他期望文件句柄的代码。在 IO::Uncompress::Unzip 的 perldocs 中有一个示例 here - Stuart Watt
谢谢。我已经更正了解压语句,使用“Name”选项指定应解压缩特定文件。 - stevenl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接