How to create zip file in perl? - perl

Hi friends i can create a zip file using files which is there in the directory where the script is currently running now i want to create zip file from various directory can anybody help me?
my code is;
use IO::Compress::Zip qw(:all);
zip [ glob("inventory_report_for_neus.xls") ] => "my.zip"
or die "Cannot create zip file: $ZipError" ;
this will produce zip file with specific files but
use IO::Compress::Zip qw(:all);
zip [ glob("..\\inventory_report_for_neus.xls") ] => "my.zip"
or die "Cannot create zip file: $ZipError" ;
this is also produce zip file but there is no file inside!

Updated
IO::Compress::Zip creates a zip file with a hierarchical structure based on the original locations of the files within the current directory.
However, a result of this is that it does not correctly handle files that are not enclosed by the current working directory.
The simplest solution is probably to change directories to the parent directory before zipping. If that is not an option, copy the files to a temporary location before zipping, or possibly use IO::Compress::Zip's more advanced features, like writing the zip file from a filehandle.

friends finally i found solution for this case..simply i've used shell command inside perl so i'll create zip file with appropriate files...code as follows.
use strict;
use warnings;
use MIME::Lite;
use Net::SMTP;
my $msg = MIME::Lite->new (
From => 'xyz#gmail.com',
To => 'thiyagu040#gmail.com',
Subject => 'with inline images',
Type =>'multipart/mixed'
) or die "Error creating mult;$!\n";
system("zip test.zip '../test_dir/report.xls'");
.
.
.
.
$msg ->( filename => test.zip,
content_type => 'application/zip',
disposition => 'attachment',
name => $filename,
);
MIME::Lite->send('smtp', 'smtp.gmail.com', Timeout=>60,AuthUser=>'xyz', AuthPass=>'remotecontrol');
$msg->send();

Related

Zipping a file with a new path

I have the following directory tree:
mydir/
mydir/bbb/
mydir/bbb/ccc/
mydir/bbb/ccc/myfile.txt
The file zips as follows:
bbb\ccc\myfile.txt
I want it to appear as
\ddd\myfile.txt
The command-line zip utility does not seem to have option. Is there another way, perhaps using Perl. I'm using a unix system.
If I understand you correctly then it looks like the Archive::Zip module will do what you need.
Once you have created an archive, you can use addFile to add an archive member whose path is different from the source. Like this
$zip->addFile( {
filename => 'mydir\bbb\ccc\myfile.txt',
zipName => 'ddd\myfile.txt',
} );
For instance, this program creates a zip archive and adds the contents of the current script (defined by $0) as a member called ddd\current.pl. The archive is then written to a file called current.zip. If you open that file using 7-Zip or similar then you will see ddd\current.pl.
use strict;
use warnings;
use Archive::Zip;
my $zip = Archive::Zip->new;
$zip->addFile( {
filename => $0,
zipName => 'ddd\current.pl',
} );
$zip->writeToFileNamed('current.zip');

PERL - renaming a file member in zip64 archive

I am changing a PERL code that does compression to be able to handle the zip64 extension.
the old code is using Archive::Zip module that can be used as follows.
# Create a Zip file
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
my $zip = Archive::Zip->new();
# Add a file from disk
my $file_member = $zip->addFile( 'xyz.pl', 'AnotherName.pl' );
Archive::Zip doesn't support zip64 extension and because of that I am using IO::Compress::Zip module instead.
I am looking for a way to mimic the addfFile functionality some way or another, renaming while zipping or maybe editing the archives after zipping.
I can't find any PERL module that can help me in doing so.
Is there any way in PERL to do that ?
In case there is not a direct way, can I change something in the
header of the archive file to rename its members ?
Thank you
I assume this is the same question you asked over on PerlMonks Renaming a file member in zip64 archive?
If so, here is the same reply.
Try this - it will automatically create the output file as a Zip64 compliant Zip archive if required (i.e. if the size exceed 4 Gig or you have > 64k members in the zip archive). Otherwise it creates a standard Zip archive.
use Archive::Zip::SimpleZip qw($SimpleZipError) ;
my $z = new Archive::Zip::SimpleZip "my1.zip"
or die "Cannot create zip file: $SimpleZipError\n" ;
$z->add('xyz.pl', Name => 'AnotherName.pl' );
$z->close();
If you want to force the creation of a Zip64 archive (even when the archive is small enough not to need it) add the Zip64 option when creating the Archive::Zip::SimpleZip object, like this
my $z = new Archive::Zip::SimpleZip "my1.zip", Zip64 => 1
or die "Cannot create zip file: $SimpleZipError\n" ;
I am not sure if there is a way to do it with IO::Compress::Zip, but.
Why do not you rename files before adding them to archive?
If you need to preserve original files with its names, copy the files to some temp folder, rename, and to archive and delete from temp after.

Zipping a file without copying its directory into the archive using Perl with IO::Compress::Zip

I am assigned the task of changing some Perl code that creates a zip archive to make it compatible with zip64 so that it can create archives more than 4 GB in size or have more than 64K members.
The old code was using Archive::Zip module which is limited to zip and doesn't include the zip64 extension. So now I am playing around with the IO::Compress::Zip module which supports zip64.
I am trying to compress two files on my desktop and place the new archive on my desktop.
Everything is working fine, but the files are not placed in the root of my archive, their whole directory is created inside the archive.
For example, I have two files in my desktop: file1 and file2 and I use the following code
use strict;
use warnings;
use IO::Compress::Zip qw(zip $ZipError) ;
my $file = $ENV{"HOME"}."/Desktop/file1";
my $file2 = $ENV{"HOME"}."/Desktop/file2";
my $s = zip [ $file1, $file2 ] => $ENV{"HOME"}."/Desktop/new_.zip" , zip64 => 1
or die "zip failed: $ZipError \n";
When I go and check my archive I find the following directory
"home"-> "mohamad" -> "Desktop"
and inside this directory I find my files.
How can I copy my files directly to the root of the archive?
Like Archive::Zip, IO::Compress::Zip will include the directories that you specify in the files to be archived. Instead of using $ENV{"HOME"}."/Desktop/ everywhere you should just
chdir "$ENV{HOME}/Desktop"
and then specify the bare filenames that you want to save. It solves your problem as well as making the code a lot tidier.
It looks like this. Note that I have used autodie to avoid having to explicitly check whether the chdir has succeeded. Also, on my Windows 7 system the correct environment variable is USERPROFILE but I imagine you are running XP or some other variant.
use strict;
use warnings;
use autodie;
use IO::Compress::Zip qw(zip $ZipError);
chdir "$ENV{HOME}/Desktop";
my $file1 = 'file1';
my $file2 = 'file2';
my $s = zip [ $file1, $file2 ] => 'new_.zip', Zip64 => 1
or die "Zip failed: $ZipError\n";
Update
As an alternative you can use the FilterName callback to modify the name stored in the zip file. To remove the path entirely is straightforward and looks like this.
use strict;
use warnings;
use IO::Compress::Zip qw(zip $ZipError);
my $file1 = "$ENV{HOME}/Desktop/file1";
my $file2 = "$ENV{HOME}/Desktop/file2";
my $s = zip [ $file1, $file2 ] => "$ENV{USERPROFILE}/Desktop/new_.zip",
FilterName => sub { s<.*[/\\]><> },
Zip64 => 1,
or die "Zip failed: $ZipError\n";
I am not a specialist in IO::Compress::Zip, but if it acts like other compression utilities/libraries, you need to cd to $ENV{"HOME"}."/Desktop/ and then compress just ["file1", "file2"]

Perl script to download a file from LAN

path is similar to this \\pc1\folder1\folder2\file.bin
Above is the shared folder on the network
and I have to save it to a path similar to c:\Users\me\Desktop\file_copy.bin
I am new to Perl and thus clear explanation of how it is happening will be appreciable.
You can try the Win32::FileOp module, below is how you open the file, you can use the CopyFile option for downloading.
use Win32::FileOp qw/ Map /;
Map 'X:' => ' \\\\machine\\share',
{ user => 'foo', passwd => 'bar' };
open FILE, 'x:/path/file.ext' or die "...";
Also check out File::Fetch

Perl Rar a whole folder

I want to rar a whole folder with Perl and Archive::Rar. For example the folder /root/pictures.
I have found only a way to rar single files.
I tried to find all files in the folder and rar them, but then I always have the whole path sticking to them (/root/pictures) in the rar archive.
I want only the /pictures folder plus its contents. Is that possible?
The folder structure of the files stored in the archive will be the same as the file names that you pass to the Add method. (Although you can add them without any containing folder at all using the -excludepaths option.)
If you chdir to the \root directory before adding the files to the archive, and specify all your files as pictures\file1.jpg etc. then the result should be as you want.
Something like this
use strict;
use warnings;
use Archive::Rar;
use autodie;
chdir '\root';
my $rar = Archive::Rar->new(-archive => 'pictures.rar');
$rar->Add(-files => [ glob 'pictures\*' ]);
Clearly you could add a path to the rar file name if you want the archive stored elsewhere.
At first you have to get a list of files from defined directory:
use File::Find;
my #content;
find( \&wanted, '/some/path');
sub wanted {
push #content, $File::Find::name;
return;
}
After that you may use the Archive::Rar to pack it.
use Archive::Rar;
my $rar = Archive::Rar->new();
$rar->Add(
-size => $size_of_parts,
-archive => $archive_filename,
-files => \#content,
);