Re: Checking if a file is present in a ZIP archive
by toolic (Bishop) on Mar 25, 2011 at 17:21 UTC
|
Sometimes, a CPAN dist will contain additional documentation in a POD file separate from the main module file.
From the Archive::Zip::FAQ: How to test file integrity?
Q: How can Archive::Zip can test the validity of a Zip file?
A:
There are two ready-to-use utilities in the examples directory that ca
+n be used to test
file integrity, or that you can use as examples for your own code:
examples/zipcheck.pl shows how to use an attempted extraction to test
+a file.
The example script uses eval and:
Archive::Zip::setErrorHandler( sub { warn shift() } );
When I run zipcheck.pl on a file which I know is not a zip file, I only get one message:
format error: can't find EOCD signature
| [reply] [d/l] [select] |
|
|
I use ActivePerl in WinXP and there is no examples directory in the Archive::ZIP package.
| [reply] |
|
|
| [reply] |
|
|
|
|
Just set the error handler to empty sub to avoid printing the warnings.
| [reply] |
Re: Checking if a file is present in a ZIP archive
by choroba (Cardinal) on Mar 25, 2011 at 17:07 UTC
|
| [reply] [d/l] [select] |
|
|
The problem is not that the file cannot be read. The file can be read just fine. However, if it happens not to be a ZIP archive, the Archive::ZIP package spews half a screen of errors from various parts of itself, essentially complaining about the missing signature and going downhill from there.
| [reply] |
|
|
Then find a way to turn those warnings into a die, for eval; for example by temporarily setting $SIG{__WARN__}; or, if the module has a way to handle errors, use that. One such warning and it's game over.
| [reply] [d/l] |
|
|
Nice guess, but that spews even more messages for me (version 1.26).
| [reply] |
Re: Checking if a file is present in a ZIP archive
by locked_user sundialsvc4 (Abbot) on Mar 25, 2011 at 19:49 UTC
|
Your decision to check for a signature is a reasonable one.
It is fairly common to take the approach of doing something in an eval block, so that, if it fails for any reason, you will be able to detect that it has done so. (The built-in variable “$@” will have a value...)
This is actually a very good way to deal with these kinds of errors:
eval {
... something that might fail ...
... (if we made it this far, we didn't fail, so) check return-code
}
if ($@) {
... guess what, it failed ...
}
else {
... it didn't ...
}
A lot of code these days is intentionally designed in such a way that, if it encounters an exceptional condition that is “plausible and reasonable,” it returns an error-code, but if it encounters a “this can’t possibly ever ever ever happen, but it just did” condition, it throws an exception via die or Carp. Maybe the designers decided that, if they are supposed to be getting a valid ZIP-file but instead they have a corrupted one (or a flat file containing the text of the Gettysburg Address...), it would be best to commit suicide. And I would not say that they were wrong.
| |
|
|
Yes, I did try trapping the error with eval but it didn't work - it still spews a bunch of errors. I haven't used eval before, so maybe I've messed something up; I'll try again.
But if the designers have decided that the archive-processing functions should be passed only valid ZIP files, then they should have also provided a function that lets the user test if a file is a valid ZIP file. For instance, the Archive::Extract package does have such a function, but I can't use that package for various reasons (it doesn't have a function for testing the presence of a file with a specified name in the archive and it requires the presence of an unarchiving program).
| [reply] |
|
|
| [reply] |
|
|
|
|
|
|
I just tried eval also (you need a semicolon after the block following eval I found out) and it was the same.
I also tried 'no warnings;' for the block containing the read($file) and that didn't help. I have always checked the file extensions before opening something but someone could clobber my file.
I'm curious now to look under the hood of Archive::Zip even though I probably won't understand it.
| [reply] |
|
|
Re: Checking if a file is present in a ZIP archive
by Gulliver (Monk) on Mar 25, 2011 at 18:51 UTC
|
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
my $zip2_path = 'c:/usr/test/file.zip';
my $zip2 = Archive::Zip->new();
unless ( $zip2->read( $zip2_path ) == AZ_OK ) {
die "$zip2_path read error";
}
It does return an error if you call it this way. It says in the module docs at cpan you can put the file name in the constructor but you don't get the error code. If you read it with an object method like this you do. Also, did you check for .zip ending? That doesn't guarantee anything but could weed out files that shouldn't be attempted to open. | [reply] [d/l] |
|
|
This is almost exactly how I tried it initially - except that I don't die with an error message; I just skip the file. It is how common sense suggests that the package should behave. But it DOES NOT! Try passing it a text file instead of a ZIP archive and you'll see. It will spew half a screen of error messages (basically complaining about the lack of signature and going downhill from there), instead of keeping silent and simply returning some error code that is not AZ_OK.
| [reply] |