Gulliver has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to remove a file from one zip file and add it to another using Archive::Zip. I keep getting incorrect crc on the file that was removed / added. The rest of the files in the archive are readable, not this one.

Update: I split the code that creates the zip files into another script to simplify for debugging and so I could verify neither is corrupt before running the remove/addMember code. Both the source zip files are created with Archive::Zip using addFile and they have no problems. I changed the code below to write to a new zip file to rule out the overwrite() function but still have the problem.

#!/usr/bin/perl use warnings; use strict; use Archive::Zip qw(:ERROR_CODES :CONSTANTS); my $zip1Name = '.\\tmp\\test1.zip'; my $zip2Name = '.\\tmp\\test2.zip'; my $zip1 = Archive::Zip->new(); my $zip2 = Archive::Zip->new(); if (!-e $zip2Name || !-e $zip1Name) { die "run test_arc.pl to create zip files for this."; } unless ( $zip1->read( $zip1Name ) == AZ_OK ) {die 'zip1 read error';} unless ( $zip2->read( $zip2Name ) == AZ_OK ) {die 'zip2 read error';} my $rm_return = $zip1->removeMember('rr.log'); if ($rm_return) { print "removeMember : ", $rm_return->fileName() ,"\n"; $zip2->addMember($rm_return) or die "Can't add ", $rm_return->fileName() ," to zip!"; } else {print "\$rm_return is undef\n";} unless ( $zip1->overwrite() == AZ_OK ) { die 'zip1 overwrite() error'; } # unless ( $zip2->overwrite() == AZ_OK){die 'zip2 overwrite() error' +;} unless ( $zip2->writeToFileNamed('.\\tmp\\newtest2.zip') == AZ_OK ) + { die 'zip2 write() error'; }

I ran the checkzip.pl script that came in the examples for Archive::Zip and get this:

Member rr.log CRC error: file says ff147173 computed: 354acf95 CRC errors found.

I'm using Strawberry Perl 5.12.0 on XP

Update: I found a workaround

Archive::Zip object method addMember() will corrupt the file it if you pass it a member obtained from removeMember( 'filename' ). I found I could use

 $zip->memberNamed( 'filename')

to get a member, then add that without it being corrupted. Then I have to go back and remove it from the first archive.

However, I found that

my $removed_member = $zip1->removeMember( 'foo' ); $removed_member->extractToFileNamed('foo');

worked fine.

Replies are listed 'Best First'.
Re: crc error in zip archive using addMember()
by roboticus (Chancellor) on Dec 03, 2010 at 11:56 UTC

    Gulliver:

    The only suspect I can think of at the moment is that the original ZIP file is corrupt (as can happen when transferring via FTP in ASCII mode, etc.).

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      I'm going to turn this in as a bug in Archive::Zip.

      Update:

      It isn't a bug, just a lack of understanding on my part. I kept going through the documentation for Archive::Zip and noticed where it says when you read an archive it is not read into memory. So when I get a member object for a file with the removeMember method it is actually just an object with a file offset into the zip file. As soon as I save the updated version of that zip file the offset is invalid.

      To make my original code work all I needed to do was save the second zip before the first one.