How to copy zipped file data to one txt file - perl

Now i need to copy data inside the zip files to one .txt file i.e all R1 folder file data should copy and save in one R1.txt file similarly R2 folder file data should save in one single R2.txt file. is it possible to copy data from zipped files??
#!/usr/bin/perl
use File::Copy;
use strict;
use warnings;
print"Enter Folder name \n";
print"File name: ";
chomp(my $Filename=<>);
mkdir "R1";
mkdir "R2";
opendir(DIR,"$Filename") or die "cannot open directory";
foreach my $name (readdir(DIR))
{
next if ($name =~ /^\./);
if($name =~ /R1/) { #compare $name not $Filename
copy("$Filename/$name", "R1"); # copy the file from folder to R1 directory
system("cat $Filename\/$name >> R1.txt");
}
elsif($name =~ /R2/){
copy("$Filename/$name","R2"); ## copy the file from folder to R2 directory
system("cat $Filename\/$name >> R2.txt");
}
}
thanks in advance.

without unzipping the file you can extract the content, the simple and easiest way to do so without using modules is, to use unix command in perl
use strict;
use warnings;
my $text = `unzip -c customer.xml.gz`;
print $text ."\n";
AFter extracting the contents, write the same into one.txt file

Related

How to check if a zip fie is empty using perl

I'm writing a Perl scipt that unzips the zip file and moves the content of zip file to a directory, however I want to skip the zip file which do not have any content in it. How can I filter these files. For unzipping the file I'm using
unzip_content = system("unzip -d <directory> -j -a <filepath>")
Could anyone suggest me anyway to check if it does not contain anything.
I tried with checking the filesize using -s $filename but later I got some files with filesize 22 byte but with no content in it.
You can use Archive::Zip to achieve all of that inside of your Perl program without shelling out. You need to check if the archive contains anything, which can be done with the numberOfMembers method.
use strict;
use warnings;
use Archive::Zip qw/:ERROR_CODES/;
my #files = ...;
foreach my $file (#files) {
my $zip = Archive::Zip->new;
# skip if archive cannot be opened
next unless $zip->read($file) == AZ_OK;
# skip if archive is empty
next unless $zip->numberOfMembers;
# extract everything
$zip->extractTree({zipName => '<directory>'});
}
An other way to check the same thing is to calculate the MD5 hash of the file. MD5 hash of all empty zip files would be 76cdb2bad9582d23c1f6f4d868218d6c.
Helpful links:
minimum size zip file
Digest::MD5
use strict;
use warnings;
use Digest::MD5 qw(md5 md5_hex md5_base64);
my $filedir = "/home/docs/file.zip";
open FILE, "$filedir";
my $ctx = Digest::MD5->new;
$ctx->addfile (*FILE);
my $hash = $ctx->hexdigest;
close (FILE);
if($hash eq '76cdb2bad9582d23c1f6f4d868218d6c')
{
# empty file
}

Perl File::Copy is not actually copying the file

Quick synopsis: Let's say there are multiple of the same file type in one directory (in this example, 10 .txt files). I am trying to use Perl's copy function to copy 5 of them into a new directory, then zip up that directory.
The code works...except the folder that is supposed to have the .txt files copied, doesn't actually have anything in it, and I don't know why. Here is my complete code:
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
my $source_dir = "C:\\Users\\user\\Documents\\test";
my $dest_dir = "C:\\Users\\user\\Desktop\\files";
my $count = 0;
opendir(DIR, $source_dir) or die $!;
system('mkdir files');
while (my $file = readdir(DIR)) {
print "$file\n";
if ($count eq 5) {
last;
}
if ($file =~ /\.txt/) {
copy("$file", "$dest_dir/$file");
$count++;
}
}
closedir DIR;
system('"C:\Program Files\Java\jdk1.8.0_66\bin\jar.exe" -cMf files.zip files');
system('del /S /F /Q files');
system('rmdir files');
Everything works...the directory files is created, then zipped up into files.zip...when I open the zip file, the files directory is empty, so it's as if the copy statement didn't copy anything over.
In the $source_dir are 10 .txt files, like this (for testing purposes):
test1.txt
test2.txt
test3.txt
test4.txt
test5.txt
test6.txt
test7.txt
test8.txt
test9.txt
test10.txt
The files don't actually get copied over...NOTE: the print "$file\n" was added for testing, and it indeed is printing out test1.txt, test2.txt, etc. up to test6.txt so I know that it is finding the files, just not copying them over.
Any thoughts as to where I'm going wrong?
I think there is a typo in your script:
system('mkdir files');
should be:
system("mkdir $dest_dir");
but, the real issue is that you are not using the full path of the source file. Change your copy to:
copy("$source_dir/$file", $dest_dir);
and see if that helps.
You might also want to look at: File::Path and Archive::Zip, they would eliminate the system calls.

How to zip only files and not the full path

I'm trying to zip up image files using Archive::Zip. The files are in Data/Temp/Files When I loop through the logs in the directory and add them to the zip file, I end up with the folder hierarchy and the image files when I only want the image files.
So the zip ends up containing:
Data
└Temp
└Files
└Image1.jpg
Image2.jpg
Image3.jpg
When I want the zip file to contain is:
Image1.jpg
Image2.jpg
Image3.jpg
Here is the script I'm running to test with:
#!/usr/bin/perl
use Archive::Zip;
$obj = Archive::Zip->new(); # new instance
#files = <Data/Temp/Files/*>;
foreach $file (#files) {
$obj->addFile($file); # add files
}
$obj->writeToFileNamed("Data/Temp/Files/Images.zip");
Use chdir to change into the directory:
use Archive::Zip;
$obj = Archive::Zip->new(); # new instance
chdir 'Data/Temp/Files';
#files = <*>;
foreach $file (#files) {
$obj->addFile($file); # add files
}
$obj->writeToFileNamed("Images.zip");
The names and paths of zip archive members are completely independent of those of their real file counterparts. Although the two names are conventionally the same, AddFile allows you to specify a second parameter which is the name and path of the corresponding archive member where the file information should be stored
You can achieve the effect you're asking for my using basename from the File::Basename module to extract just the file name from the complete path
This program demonstrates. Note that it is essential to use strict and use warnings at the top of every Perl program you write
use strict;
use warnings;
use Archive::Zip;
use File::Basename 'basename';
my $zip = Archive::Zip->new;
for my $jpg ( glob 'Data/Temp/Files/*.jpg' ) {
$zip->addFile($jpg, basename($jpg));
}
$zip->writeToFileNamed('Data/Temp/Files/Images.zip');

rename the txt file extension using perl

I am doing the below steps:
Read all the text files in a directory and store it in an array named #files
Run a foreach loop on each text file. Extract the file name(stripping of .txt) using split operation and creating a folder of that particular filename. Rename that file to Test.txt (so as to work as input fo another perl executable) Executing test.pl for each file by adding the line require "test.pl";
It works fine for only one file, but not any more. Here is my code:
opendir DIR, ".";
my #files = grep {/\.txt/} readdir DIR;
foreach my $files (#files) {
#fn = split '\.', $files;
mkdir "$fn[0]"
or die "Unable to create $fn[0] directory <$!>\n";
rename "$files", "Test.txt";
require "test3.pl";
rename "Test.txt", "$files";
system "move $files $fn[0]";
}
you don't require the file to be loaded once, but done every time.
So, replace
require "test3.pl";
with
do "test3.pl";
Can you glob for files in that directory..
Replace,
opendir DIR, ".";
my #files = grep {/\.txt/} readdir DIR;
with,
my #files = <*.txt>;

How to read multiple files from a directory, extract specific strings and ouput to an html file?

Greetings,
I have the following code and am stuck on how I would proceed to modify it so it will ask for the directory, read all files in the directory, then extract specific strings and ouput to an html file? Thanks in advance.
#!/usr/local/bin/perl
use warnings;
use strict;
use Cwd;
print "Enter filename: "; # Should be Enter directory
my $perlfile =STDIN;
open INPUT_FILE, $perlfile || die "Could not open file: $!";
open OUTPUT, '>out.html' || die "Could not open file: $!";
# Evaluates the file and imports it into an array.
my #comment_array = ;
close(INPUT_FILE);
chomp #comment_array;
#comment_array = grep /^\s*#/g, #comment_array;
my $comment;
foreach $comment (#comment_array) {
$comment =~ /####/; #Pattern match to grab only #s
# Prints comments to screen
Print results in html format
# Writes comments to output.html
Writes results to html file
}
close (OUTPUT);
Take it one step at a time. You have a lot planned, but so far you haven't even changed your prompt string to ask for a directory.
To read the entered directory name, your:
my $perlfile =STDIN;
gives an error (under use strict;). Start by looking that error up (use diagnostics; automates this) and trying to figure out what you should be doing instead.
Once you can prompt for a directory name and print it out, then add code to open the directory and read the directory. Directories can be opened and read with opendir and readdir. Make sure you can read the directory and print out the filenames before going on to the next step.
a good starting point to learn about specific functions (from the cmd line)
perldoc -f opendir
However, your particular problem is answered as follows, you can also use command line programs and pipe them into a string to simplify file handling ('cat') and pattern matching ('grep').
#!/usr/bin/perl -w
use strict;
my $dir = "/tmp";
my $dh;
my #patterns;
my $file;
opendir($dh,$dir);
while ($file = readdir($dh)){
if (-f "$dir/$file"){
my $string = `cat $dir/$file | grep pattern123`;
push #patterns, $string;
}
}
closedir($dh);
my $html = join("<br>",#patterns);
open F, ">out.html";
print F $html;
close F;