Archive::Zip reading from a scalar

Recently I spent a day trying to get Archive::Zip to open an existing zip file which was already loaded into memory (and stored in a scalar variable). It just wouldn’t work, so I tried the simplest possible example in a separate file, and it still wouldn’t work. Eventually I discovered a solution, though not perfect, it works for me, and I hope you can use it.

The simplest example of the functionality was included as one of the example files, readScalar.pl. This file uses IO::File to load a zip file into a scalar variable, and then uses IO::Scalar to open a seekable filehandle to that scalar which Archive::Zip can use with it’s readFromFileHandle method to load in the zip file.

Unfortunately, even this example wasn’t running on both my Mac OS X box or my CentOS box. I was getting an error that looked like this:

error: file not seekable
at /Library/Perl/5.8.6/Archive/Zip/Archive.pm line 437
Archive::Zip::Archive::readFromFileHandle('Archive::Zip::Archive=HASH(0x18e0700)', 'IO::Scalar=GLOB(0x1917dd8)') called at ./readScalar.pl line 20

After some Google searching, I came upon some bug reports on CPAN that dealt with this:

http://rt.cpan.org/Public/Bug/Display.html?id=7855
http://rt.cpan.org/Public/Bug/Display.html?id=7633

They both promised that the problem would be fixed in the next major release of Archive::Zip, but here we are, a couple years later, and it still doesn’t work.

The solution that worked for me was a combination of the user-submitted fixes. At the end of my perl script, I overrided Archive::Zip::Archive’s _isSeekable method with code suggested by NEDKONZ, and it looks like this:


# Override the _isSeekable function in Archive::Zip
no warnings 'redefine';
package Archive::Zip::Archive;
sub _isSeekable {
    my $fh = shift;
    if ( UNIVERSAL::isa( $fh, 'IO::Scalar' ) )
    {
        return $] >= 5.006;
    }
    elsif ( UNIVERSAL::isa( $fh, 'IO::String' ) )
    {
        return $] >= 5.006;
    }
    elsif ( UNIVERSAL::can( $fh, 'stat') )
    {
        return -f $fh;
    }
    return UNIVERSAL::can( $fh, 'seek');
}
use warnings 'all';

This function living in the bottom of my code ended the “error: file not seekable” problem. Of course, you could also just edit your Archive/Zip/Archive.pm file and fix it forever, rather than including this function in every file that needs to read a Zip file from memory.

One Response to “Archive::Zip reading from a scalar”

  1. Eugene Says:

    This helped me a lot. I think I should repost the tip in my blog.

Leave a Reply

Javascript is required in order to leave a reply. If it is not currently enabled in your web browser, please enable it, and refresh this page before writing your reply. We are using wp-hashcash, a comment-spam prevention program which requires Javascript. The benefit is that you won't be reading comments about Viagra or other pharmaceuticals.