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

Is there anyway which I can read a .txt file under 2 levels of compression. For example, 1.txt is zip to 1.zip. Later it is zipped into all.zip along with other zip files. How can I read the 1.txt?

So far I can read a .txt file in a single level of compression so I was wondering if there are any methods that can help me solve the problem above.

--Resolved--
All Credit goes to Bart

Working Source Code:
#!/usr/bin/perl use IO::Uncompress::Unzip qw(unzip $UnzipError); my $file = 'all.zip'; my $inner; unzip $file, \$inner, Name => '1.zip'; my $txt; unzip \$inner, \$txt, Name => 'ReadMe.txt'; print "$txt\n";

Replies are listed 'Best First'.
Re: Reading a .txt file under 2 levels of compression
by Anonymous Monk on Jan 11, 2011 at 13:55 UTC
    So far I can read a .txt file in a single level of compression ...

    There is no difference between one and two, just repeat your working solution for one

      Code from my previous post ---------------------------------------------------------------------

      #!/usr/bin/perl use IO::Uncompress::Unzip qw(unzip $UnzipError); my $file = 'all.zip'; my $inner; unzip $file, \$inner, Name => '1.zip'; my $txt; unzip \$inner, \$txt, Name => 'ReadMe.txt'; print "$txt\n";
      Edited Code to start reading from Tar then any zip/gz file ---------------------------------------------------------------------
      #!/usr/bin/perl use Archive::Tar; use IO::Compress::Gzip qw(gzip $GzipError); use IO::Uncompress::Gunzip qw(gunzip $GunzipError); use IO::Uncompress::Unzip qw(unzip $UnzipError); use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError +); my $tar = Archive::Tar->new; #my $inner; $tar->read('test.tar'); $inner = $tar->get_content('1.zip'); #$tar->extract_file('1.zip', \$inner); anyuncompress \$inner, \$txt, Name => '3.txt'; #unzip \$inner, \$txt, Name => 'ReadMe.txt'; #works #gunzip 'test.gz', $txt; #doesn't work print "$txt\n";
      Hi all Perl Monks, I have a question. How can I use anyuncompress to uncompress and load a zip/gz file onto a reference? Above is the work I have done so far, the major issue is with the second part of uncompressing a reference file other than zip.
        anyuncompress doesn't take a Name parameter. Try
        anyuncompress \$inner => \$txt;
        If you are only dealing with gzip files, then use this
        gunzip \$inner => \$txt;
      i believe there is. The first level de-compression will only either yield the content or file hash location. I can solve the problem if I can push the file hash location into another zip object file.
        That doesn't make any sense.
        my $zipinzip = unzipone('zipinazip'); my $final = unzipone($zipinzip); print "finished\n";
Re: Reading a .txt file under 2 levels of compression
by bart (Canon) on Jan 11, 2011 at 23:24 UTC
    The simple approach would be to decompress the external ZIP file into a temporary file, and then open that temp ZIP file.

    But it would be cleaner, from a purist point of view, to skip using temp files and uncompress the ZIP file directly into RAM.

    And by the looks of it, it seems IO::Uncompress::Unzip can do just that:

    A top-level function, unzip, is provided to carry out "one-shot" uncompression between buffers and/or files. (emphasis mine)

    unzip $input => $output [, OPTS]
    unzip expects at least two parameters, $input and $output.
    If $input is a scalar reference, the input data will be read from $$input.
    If $output is a scalar reference, the uncompressed data will be stored in $$output.
    For OPTS, you'll need at least this — because a ZIP file can contain lots of files, and you have to select one:
    Name => "membername"
    Open "membername" from the zip file for reading.
      that is exactly what I want to avoid: unziping temp files. I don't quite get your explanation. Does the code unzip $input => $output , OPTS work for the straight forward solution of unzipping all files or does it extract only the zip file inside the compiled zip file? A bit more code would greatly help in my understanding. Thank you for response!
        Well, from my understanding of the docs (of which I quoted parts in my previous post), this ought to extract the inner ZIP file from the outer ZIP file, into a string:
        use IO::Uncompress::Unzip qw(unzip $UnzipError); my $file = '2.zip'; my $inner; unzip $file, \$inner, Name => '1.zip';
        after which you can continue:
        my $txt; unzip \$inner, \$txt, Name => '1.txt';
        and now the text will be in the string $txt. (Caveat: untested)

        Apparently the "Name => $name" part is optional if the ZIP archive contains only one file (what they call a "member file"):

        Say you have a zip file, file1.zip, that only contains a single member, you can read it and write the uncompressed data to the file file1.txt like this.
        unzip $input => $output or die "unzip failed: $UnzipError\n";

        If you have a zip file that contains multiple members and want to read a specific member from the file, say "data1", use the Name option

        unzip $input => $output, Name => "data1" or die "unzip failed: $UnzipError\n";
        I think you'll find that reading the documentation (perldoc IO::Uncompress::Unzip) will help your understanding even more than being spoonfed its content.

        Or, at a minimum, doing so and demonstrating that you have with some question not clearly answered there, would at least belie your chosen nick.