【问题标题】:Getting "format error: can't find EOCD signature" with archives使用存档获取“格式错误:找不到 EOCD 签名”
【发布时间】:2019-06-21 02:52:03
【问题描述】:

下面的代码工作正常,除了一些 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 文件有什么问题。

提前致谢

【问题讨论】:

  • 如果无法解决,至少我需要一个解决方案来忽略这些错误

标签: windows file perl zip


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

在 Perl(die)中处理异常的内置方法是通过 eval 的块形式。 另请参阅 $@ 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+$@ 以便于消化,也许更容易正确使用。

【讨论】:

  • 感谢分享知识。看起来很有意义。我试试这个。
  • @SiddaramuKS 太好了。这应该工作,让我知道它是怎么回事。
猜你喜欢
  • 2018-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多