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

Great Monks! I am trying to unzip some .txt files using IO::Uncompress::Unzip in the code snippet below. Am getting this error though, which i suspect is to do with unseen folders in windows;
.
Use of uninitialized value $_1 in string eq at C:/Strawberry/perl/lib/IO/Compress/Base/Common.pm line 280. unzip failed: input file '.' is a directory

Below is the code

opendir(ZIPPED, $zipdir)or die "couldn't open $zipdir: $!\n"; my @zd = readdir(ZIPPED); my @uzd; foreach(@zd) { my $inf = $_; my $outf = $uzd[@uzd]; # print $_,"\n"; unzip $inf => $outf or die "unzip failed: $UnzipError\n"; }

Below is sample of the output i get if i run the print line and comment out the unzip line;
.
..
730372_Atoll.zip
730376V01_Atoll.zip
730378V01_Atoll.zip
730691_Atoll.zip
732689_Atoll.zip
732690_Atoll.zip
732691_Atoll.zip
How can i get past the "." and ".." and get unzip to uncompress the files. Thanks!

Replies are listed 'Best First'.
Re: unzip fail using IO::Uncompress::Unzip
by Marshall (Canon) on Sep 23, 2016 at 17:05 UTC
    You could use grep to filter out directories from the readdir output. There could be other directories than "." and ".." in there. Note that readdir does not return the complete path the the file name, just the name. You probably need to pre-pend the zipdir name to any usage of these names later in the code.
    my @zd = grep {!-d "$zipdir/$_"}readdir(ZIPPED);
    What do you intend for this to do? my @uzd; my $outf =  $uzd[@uzd];?

      Thanks great monks! I have tried Marshalls construct and successfully removed the "." and ".." directories. the code now looks as below



      opendir(ZIPPED, $zipdir)or die "couldn't open $zipdir: $!\n"; my @zd = grep {!-d "$zipdir/$_"}readdir(ZIPPED); opendir(UNZIPPED, $unzipdir)or die "couldn't open $unzipdir: $!\n"; my @uzd = readdir(UNZIPPED); foreach(@zd) { next unless defined $_; my $inf = \@zd; my $outf = \@uzd; #print $_,"\n"; unzip $inf => $outf or die "unzip failed: $UnzipError \n"; }

      I am still unable to unzip, the error I get is as below
      Uncaught exception from user code:
      unzip failed: input file '730372_Atoll.zip' does not exist
      That is the first file in the folder.
      And Marshall, the 'my @uzd; my $outf = $uzd@uzd' was intended to be an assignment of the unzipped files to an array,
      but i revised as shown in the code above.
      So monks, what should i improve on? Thanks in advance!

        "unzip failed: input file '730372_Atoll.zip' does not exist"
        That looks like a directory problem. Remember that readdir only returns the file name, not the a complete path to the file. You need "$zipdir/730372_Atoll.zip" otherwise the .zip file is expected in the current directory wherever the Perl script is running. You could add the full file path instead of just the file names from readdir into @zd array by using map:
        my @zd = grep {!-d}map{"$zipdir/$_"}readdir(ZIPPED);

        I looked at IO::Uncompress::Unzip I suspect that you are using the wrong tool. If you unzip $inref => $outref and my $inref = \@zd;, that is fine. However, your assignment of filenames to the output arrary ref is meaningless. see Notes:

        When $input_filename_or_reference maps to multiple compressed files/buffers and $output_filename_or_reference is a single file/buffer, after uncompression $output_filename_or_reference will contain a concatenation of all the uncompressed data from each of the input files/buffers.
        You will just get a bunch of concatenated junk in @uzd.

        Try reading Archive::Extract and look at Re: Archive::Zip for unzipping to directory?

        Try writing some code that just extracts one .zip file using a hard coded name and puts the contents where you want it, then work on making a loop with varying dir contents.

        readdir is raw eggs, what you want is cake

        #!/usr/bin/perl -- use strict; use warnings; ## Main( @ARGV ); Main( "zipdir", "unzipdir" ); exit( 0 ); sub Main { my( $zipdir, $unzipdir ) = @_; my @zipped = GetZipFiles( $zipdir ); my @unzipped = GetZipFiles( $unzipdir ); if( @zipped == @unzipped ){ MatchBanana( \@zipped, \@unzipped ); } else { die "zipped number not equal to unzipped number, bye!\n"; } } sub MatchBanana { my( $zip, $unzip ) = @_; for my $ix ( 0 .. $#{$zip} ){ my $inf = $zip->[$ix]; my $outf = $unzip->[$ix]; unzip $inf, $outf or die "unzip failed: $UnzipError \n"; } } sub GetZipFiles { use Path::Tiny qw/ path /; my( $zipdir ) = @_; my @zipfiles = path( $zipdir )->children( qr/\.zip$/i ); return @zipfiles; }

        Even this program has problems, the zipfiles arent sorted , whos to say the infile really go with the outfiles

Re: unzip fail using IO::Uncompress::Unzip
by toolic (Bishop) on Sep 23, 2016 at 16:38 UTC
    File::Slurp has a function to exclude . and ..
    my @zd = read_dir($zipdir);

    You may need to prepend the directory name to each file before you unzip ("prefix" option).

Re: unzip fail using IO::Uncompress::Unzip
by Anonymous Monk on Sep 23, 2016 at 17:51 UTC

    Or you could do something like this:

    foreach my $zipfile (glob "$zipdir/*.zip") { ... }