使用存档获取“格式错误:找不到EOCD签名”

时间:2019-01-28 06:00:38

标签: windows perl zip

下面的代码工作正常,除了一些zip文件我遇到错误

format error: can't find EOCD signature 
 at C:/LegacyApp/perl/lib/Archive/Zip/Archive.pm line 695
    Archive::Zip::Archive::_findEndOfCentralDirectory('Archive::Zip::Archive=HASH(0x375a730)', 'IO::File=GLOB(0x380eb90)') called at C:/LegacyApp/perl/lib/Archive/Zip/Archive.pm line 581
    Archive::Zip::Archive::readFromFileHandle('Archive::Zip::Archive=HASH(0x375a730)', 'IO::File=GLOB(0x380eb90)',

使用下面的代码:

use Archive::Zip;

unzip($zipfile,$folder,$out);

sub unzip {
    my ($archive, $want, $dir) = @_;
    my $zip = Archive::Zip->new($archive);
    foreach my $file ($zip->members) {      
        if (($file->fileName =~ /VERSION\/(.*?).cosipa.xlsx$/i)) {
            $zip->extractMember($file,$dir.$file->fileName);
        }
        if ($file->fileName =~ /VERSION\/(.*?).txt$/i) {
            $zip->extractMember($file,$dir.$file->fileName);
        }
    }
    return 1; 
}

如果我删除该特定的zip文件,则可以正常工作。但是,我需要一个能够同时处理这些zip文件的解决方案,如果可能的话,请让我知道代码和zip文件中的错误。

预先感谢

1 个答案:

答案 0 :(得分:1)

似乎其中一些文件确实存在格式错误。然后,您可以捕获这些故障并处理错误的文件(记录名称或删除文件等),否则可以正常进行。

如果显示的“错误”是一个异常(程序死了),那么您可以捕获并处理该错误

eval { unzip($zipfile, $folder, $out) };
if ($@) {
    say "Error: $@";
    # Interrogate. (Is it the expected error or some other?)
    # handle it: record the filename for later/delete it/etc ...
}

在Perl中处理{exception(仅die)“异常”的一种内置方法是通过eval的(块形式)。 另请参见the $@ error variable in perlvar

如果您的消息仅是警告,并且程序继续运行,则eval将无法捕获该消息。一种检测到这种情况的方法是安装一个SIG{__WARN__}钩子并在其中抛出一个die,然后使用与上面相同的eval

# Block, so the change to how warnings work is scoped as tight as possible
HANDLE_ZIP: {
    local $SIG{__WARN__} = sub {
        die  $_[0] if $_[0] =~ /^\s*format error:/;  # raise exception, or
        warn $_[0];                                  # re-emit the warning
    };

    eval { unzip($zipfile, $folder, $out) };
    if ($@) {
        # same as above...
    }
};

现在,如果从unzip中发出警告,而不是打印警告,则会调用具有分配给$SIG{__WARN__}的引用的子对象。然后,如果警告消息与该正则表达式匹配,则将引发die,并带有该消息。由于这是在eval内部发生的,因此如上所述。参见%SIG in perlvar

另一种方法是简单地在$SIG{__WARN__}中针对任何警告引发异常(仅在此块内!),然后在eval的处理程序中处理所有详细信息。请注意,local在这里至关重要,因此我们不会更改警告在所有代码中的工作方式。

这是一个草图(即使它可以按原样工作)。请研究链接的文档。


曾经有一些微妙的陷阱,可以直接处理$@(v5.14之前)。虽然已经解决了所有问题,但所有这些的确是低级的,考虑使用模块代替可能是一个好主意。这样可以包装eval + $@以便于消化,也可能有助于正确使用。

请寻找替代方案,但请记住,时尚一直在变化,并且许多年来已经出现和消失了。这是最近的discussion中的一些选项。