0

I am trying to extract a ZIP file in Perl. In my script, i can detect a ZIP file, i can select this .zip but after ?

    elsif ( $$file{'ccname'} =~ /(\.zip)$/x )
    {
        # Extraction ZIP
        my $zip_path=

Could you help me ?

Regards,

  • 3
    Use [Archive::Zip](http://search.cpan.org/~phred/Archive-Zip-1.45/lib/Archive/Zip.pm) – Jens Feb 12 '15 at 08:39
  • Use external command execute - http://stackoverflow.com/questions/2461472/how-can-i-run-an-external-command-and-capture-its-output-in-perl – Kostia Shiian Feb 12 '15 at 08:57
  • @KostiaShiian: Why using external command? – Toto Feb 12 '15 at 09:17
  • @JE SUIS CHARLIE: Why not? We can run external program over system call like: my $res = system($7zpath,"a",$arc_file_path,$directory_path) and control result execution using $res variable. – Kostia Shiian Feb 12 '15 at 09:31
  • @KostiaShiian: Because it's better to use a module like Archive::Zip. – Toto Feb 12 '15 at 09:33
  • @JE SUIS CHARLIE: I have just proposed an alternative solution – Kostia Shiian Feb 12 '15 at 09:42
  • There are plenty of Perl modules that will do this. One `IO::Uncompress::Unzip` is a standard module. No need to use an external command that may work differently from system to system. – David W. Feb 12 '15 at 18:58

3 Answers3

0

The tool for this job is the Archive::Zip module.

my $somezip = Archive::Zip->new();
unless ( $somezip->read( 'someZip.zip' ) == AZ_OK ) {
    die 'read error';
}

and

my @members = $zip->members();
Sobrique
  • 52,974
  • 7
  • 60
  • 101
0

Here is an example :

use strict;
use warnings;

use Archive::Extract;

my $extractor = Archive::Extract->new( archive => 'yourZippedfileName.zip' );
$extractor.extract;     #extract the files to the current working directory
serenesat
  • 4,611
  • 10
  • 37
  • 53
0

I've actually just did this for a program I wrote. I used IO::Uncompress::Unzip which is a standard module in Perl. This took me a while to piece together. The explanation for IO::Uncompress::Unzip isn't the greatest, and it took a bit of trial and error.

These are the main points:

  • You have to watch the exit status of the methods in IO::Uncompress::Unzip. If the status is less than zero, you have a problem. In that case, just die.
  • There's an outer loop that pulls out the names of the nextStream. From here, you can get the Name of the stream which will be your file and directory name.
  • Once you have the name, you have to build the path to the name. For example, if Name is foo/bar/barfu/foobar.txt, you need to make sure foo/bar/barfu exists, so you can write out foobar.txt
  • There is an inner while loop to read from the stream's buffer and write to the file itself. This has to be a loop because it might take several attempts before you've read the whole stream. This is what took me a while to realize.
  • I use IO::File which isn't necessary. I did this because everything else in this program was Object Oriented, and I figured it was time to try out the OO interface for file reading and writing. It adds nothing but confusion. Use open and print or say directly as you would in standard Perl.
  • I use File::Spec to join together the directories and file names. It's officially the correct way to join together file and directory names. After all, you don't know if you have to run your program on a Vax or a Mac Plus running System 7. If you know you're only running on Windows, Linux, Unix, or Mac OS X, you can get away with $directory/$file instead of File::Spec->join($directory, $file). Just don't blame me if your boss is upset that your script can't run on his PDP-11.

Here's an excerpt from my program:

#! /usr/bin/env perl

use strict;
use warnings;
use feature qw(say);

use File::Basename qw(basename dirname);
use File::Path qw(make_path remove_tree);
use File::Spec;
use File::Temp qw(tempfile tempdir);
use IO::File;
use IO::Uncompress::Unzip;


sub update_zip { 
    my $old_zip_file = shift;
    my $old_version  = shift;
    my $new_version  = shift;

    my $zip_directory_name = dirname $old_zip_file;
    my $zip_file_name = basename $old_zip_file;
    my $unzip_directory = tempdir(
        "$old_zip_file.XXXX",
        DIR => $zip_directory_name,
    );
    #
    # Unzip Artifact
    #
    my $zip_fh = IO::Uncompress::Unzip->new( $old_zip_file )
        or die qq(Cannot open zip "$old_zip_file" for reading.);
    #
    # Go through each element in Zip file
    #
    while ( my $status = $zip_fh->nextStream ) {
        if ( $status < 0 ) {
            die qq(Error in Zip: $IO::Uncompress::Unzip::UnzipError.);
        }
        my $element_name = $zip_fh->getHeaderInfo->{Name};
        next if $element_name =~ m{/$};      # Skip Directories
        my $element_dir = dirname $element_name;
        my $full_element_dir = File::Spec->join( $unzip_directory, $element_dir );
        my $full_element_name = File::Spec->join( $unzip_directory, $element_name );
        if ( not -d $full_element_dir ) {
            make_path $full_element_dir
                or die qq(Can't make directory "$full_element_dir".);
        }
        my $unzipped_fh = IO::File->new( $full_element_name, "w" )
            or die qq(Can't open file "$full_element_name" for writing: $!);
        my $buffer;
        while ( my $status = $zip_fh->read( $buffer ) ) {
            if ( $status < 0 ) {
                die qq(Error in Zip: $IO::Uncompress::Unzip::UnzipError.);
            }
            $unzipped_fh->write( $buffer );
        }
        $unzipped_fh->close;
    }
    $zip_fh->close;
}
David W.
  • 105,218
  • 39
  • 216
  • 337
  • This works great, except it reprocesses the last ZIP file entry over and over again in an infinite loop. Suggest adding " && !$zip_fh->eof " to the while() condition. – livefree75 Jun 28 '23 at 18:48