首页 > 解决方案 > 使用存档获取“格式错误:找不到 EOCD 签名”

问题描述

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

格式错误:找不到 EOCD 签名
 在 C:/LegacyApp/perl/lib/Archive/Zip/Archive.pm 第 695 行
    Archive::Zip::Archive::_findEndOfCentralDirectory('Archive::Zip::Archive=HASH(0x375a730)', 'IO::File=GLOB(0x380eb90)') 在 C:/LegacyApp/perl/lib/Archive 调用/Zip/Archive.pm 第 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 文件有什么问题。

提前致谢

标签: windowsfileperlzip

解决方案


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

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

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 ...
}
# control returns here, unless the block above does exit/die/croak/goto

在 Perl(模具)中处理异常的一种内置方法是通过eval的块形式。†</sup> 另请参阅$@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__}。然后,如果警告的消息与该正则表达式匹配,则将 adie与该消息一起抛出。由于这是在内部触发的,eval因此会像前面的代码示例一样对其进行处理。见%SIGperlvar

另一种方法是简单地为任何警告引发异常$SIG{__WARN__}(仅在此块内!),然后处理eval's 处理程序中的所有细节。

请注意,本地在所有这些中都很重要,因此我们不会更改警告在所有代码中的工作方式,而只是在此块中。

这应该可以正常工作,但请研究链接的文档。


†</sup> 曾经有$@直接处理的微妙陷阱(在 v5.14 之前)。虽然这已经解决了,但所有这些确实是低级的,考虑使用模块可能是个好主意。这将包裹eval+$@以便于消化,并且可能更容易正确使用。


推荐阅读