How do I archive a set of files using Perl on Win32 while retaining file paths?
PROBLEM FOUND. I'm leaving the question here, though, in case others run into the same problem I ran into.
It looks like I encountered a bug or a weird feature in WinZip 11. When I double click the test2.zip file to see its contents, WinZip tells me the path to the data file is "allcapsname" in lower case, but when WinZip extracts the archive (from a right-click Extract to here menu), it actually creates the 开发者_如何学Go"ALLCAPSNAME" directory properly. I was complaining about a problem I thought I was having with Archive::Zip and it was a WinZip problem the whole time. Thanks to all who helped figure out what was wrong.
Turns out that to get the path to show up in WinZip file while using Archive::Tar, you need this line in your code to force Archive::Tar to deviate from strict POSIX compliance: $Archive::Tar::DO_NOT_USE_PREFIX = 1;
ORIGINAL QUESTION: I've found a handful of various Perl modules so far that appear to be capable of creating ZIP or GZIP or TAR or TGZ archive files from within my Perl scripts, but I haven't actually had complete success from any of them. Why is this so hard? Is it because I'm on a Windows machine? (I've wasted about 4 hours on this seemingly simple task so far and am really getting frustrated.)
When I tried Archive::Tar I had success creating the archive file, but I was not able to get the paths to any of my files included in the tarball for some reason or another. I tried a bunch of different things in my code and my tarball always showed the files in there with empty paths. (I'm looking at my tarballs using WinZip.)
When I tried Archive::Zip I had more success and I got the actual directory path to my files included in the archive file. The only problem was that my path to my files was somewhere along the way changed from upper case to lower case. Why did it change the case of my directory? I want the actual directory name to remain exactly as it was.
I tried a few other modules without any success. I can't even get the sample code from Archive::Builder to even compile.
ORIGINAL QUESTION ADDENDUM:
I have finally been able to create a minimal executable script that clearly demonstrates my 2 problems that I described above regarding Archive::Zip and Archive::Tar.
use strict;
use warnings;
use Archive::Zip;
use Archive::Tar;
print "Starting...\n";
# Archive::Zip Synopsis (relative path to directory)
my $zip1 = Archive::Zip->new();
$zip1->addFile( 'MyArchiveFiles/file1.txt' )
or die 'unable to add file to archive';
$zip1->writeToFileNamed('test1.zip');
# Archive::Zip Synopsis (with ALL CAPS DIRECTORY NAME)
my $zip2 = Archive::Zip->new();
$zip2->addFile( 'ALLCAPSNAME/file1.txt' )
or die 'unable to add file to archive';
$zip2->writeToFileNamed('test2.zip');
# Archive::Tar Synopsis (relative path to directory)
my $tar3 = Archive::Tar->new;
$tar3->add_files( 'MyArchiveFiles/file1.txt' )
or die 'unable to add file to archive';
$tar3->write('test3.tar');
print "Finished successfully!";
This script creates 3 archives. The first archive contains the data file with the appropriate path of "MyArchiveFiles\". My problem occurs when my directory name is all caps. The second archive contains the data file, but the path in the archive file is not "ALLCAPSNAME\" as expected ... it is "allcapsname\". This is a problem for me. Why did it change the case of my path and how can I force it to leave it alone?
The third archive contains the data file but it contains an empty path for that file. This is a problem for me. I need the path to be in the archive so that when I unpack the archive the files are extracted into the appropriate directory structure.
Do you have a specific question? The following code works perfectly fine on Win32:
#!/usr/bin/perl
use strict;
use warnings;
use Archive::Zip;
use File::Find;
my $zip = Archive::Zip->new;
find(\&wanted, $ENV{TEMP});
$zip->writeToFileNamed('test.zip');
sub wanted {
return unless /\.txt$/;
$zip->addFile($File::Find::name);
}
Let's run it:
C:\Temp> arc C:\Temp> unzip -l test.zip Archive: test.zip Length Date Time Name -------- ---- ---- ---- 240 10-16-09 19:19 /Temp/cpan_install_Wb7z.txt 2401 10-18-09 23:09 /Temp/perldoc_perlfunc_T4adbd85e_aec9c.txt 2401 10-18-09 23:09 /Temp/perldoc_perlfunc_T4adbd872_bc437.txt 2718 10-19-09 10:04 /Temp/perldoc_perlfunc_T4adc71e7_f4c64.txt 2718 10-19-09 10:04 /Temp/perldoc_perlfunc_T4adc71f2_bf08d.txt 2718 10-19-09 10:04 /Temp/perldoc_perlfunc_T4adc720a_a5c6a.txt 29188 10-19-09 10:05 /Temp/perldoc_perlfunc_T4adc7226_bd834.txt 6949 10-20-09 17:31 /Temp/perldoc_perlfunc_T4ade2c1f_d0cf8.txt 6949 10-20-09 17:32 /Temp/perldoc_perlfunc_T4ade2c50_f2040.txt 106763 10-19-09 10:00 /Temp/perldoc_perlop_T4adc7103_f4cab.txt 67948 10-18-09 23:07 /Temp/perldoc_perlvar_T4adbd7d7_d8cda.txt -------- ------- 230993 11 files
Ditto for Archive::Tar
.
Update: To clear up any doubt that the files were added to the archive with the correct path, note:
C:\Temp> dir *.txt Volume in drive C is **** Volume Serial Number is ****-**** Directory of C:\Temp 2009/10/16 07:19 PM 240 cpan_install_wb7z.txt 2009/10/18 11:09 PM 2,401 perldoc_perlfunc_t4adbd85e_aec9c.txt 2009/10/18 11:09 PM 2,401 perldoc_perlfunc_t4adbd872_bc437.txt ...
Speaking as the author of Archive::Builder, it is almost certainly not what you want.
It's meant for generating ZIP files in memory using a mix of disk and code-generated content, not for archiving.
I hear your frustration of simple things sometimes with perl on win32. If all else fails, just get a command-line version of 7-zip doing what you want, and then do a system() call to it.
I am going to answer the points raised in the new information you added to the post. I ran your script. Here are the results:
C:\Temp\a> unzip -l test1.zip Archive: test1.zip Length Date Time Name -------- ---- ---- ---- 0 10-21-09 13:03 MyArchiveFiles/file1.txt -------- ------- 0 1 file
C:\Temp\a\d> unzip ../test1.zip Archive: ../test1.zip extracting: MyArchiveFiles/file1.txt C:\Temp\a\d> dir /s ... Directory of C:\Temp\a\d 2009/10/21 01:09 PM MyArchiveFiles Directory of C:\Temp\a\d\MyArchiveFiles 2009/10/21 01:03 PM 0 file1.txt
C:\Temp\a\d> unzip ..\test2.zip Archive: ..\test2.zip extracting: ALLCAPSNAME/file1.txt C:\Temp\a\d> dir /s Directory of C:\Temp\a\d 2009/10/21 01:11 PM ALLCAPSNAME 2009/10/21 01:09 PM MyArchiveFiles Directory of C:\Temp\a\d\ALLCAPSNAME 2009/10/21 01:07 PM 0 file1.txt
C:\Temp\a\d> tar -xvf ..\test3.tar tar: Record size = 3 blocks MyArchiveFiles/file1.txt C:\Temp\a\d> dir /s 2009/10/21 01:13 PM MyArchiveFiles Directory of C:\Temp\a\d\MyArchiveFiles 2009/10/21 01:03 PM 0 file1.txt
I cut away some of the extraneous output from dir
, but I hope this makes it obvious once and for all that whatever problems you are experience are not due to Windows or Perl or Archive::Tar
or Archive::Zip
.
For the record:
C:\Temp> perl -v This is perl, v5.10.1 built for MSWin32-x86-multi-thread (with 2 registered patches, see perl -V for more detail) Copyright 1987-2009, Larry Wall Binary build 1006 [291086] provided by ActiveState http://www.ActiveState.com Built Aug 24 2009 13:48:26
C:\Temp> perl -MArchive::Tar -e "print $Archive::Tar::VERSION" 1.52
C:\Temp> perl -MArchive::Zip -e "print $Archive::Zip::VERSION" 1.30
C:\Temp> tar --version tar (GNU tar) 1.21
C:\Temp> unzip -v UnZip 5.52 of 28 February 2005, by Cygwin. Original by Info-ZIP.
The answer turned out to be an issue with WinZip 11. So if you're looking at your Archive::Zip files using WinZip, just ignore the fact that the all upper case paths are changed to all lower case in the WinZip GUI because when you actually unzip it, the path will be all upper case as intended.
As far as the Archive::Tar problem of not seeing any path at all in WinZip, you need to force Archive::Tar to deviate from strict POSIX compliance with the following line and then you will see the paths in WinZip:
$Archive::Tar::DO_NOT_USE_PREFIX = 1;
精彩评论