Zipping a file with perl results in an invalid archive - perl

I am currently trying to zip some files with perl. The resulting file is printed, so a user who calls the page which executes the script can download or open the zip file.
Looking at the size of the zip file it seems everything worked ok, but if I try to open the file on the server no contents are shown. If I open the file after downloading it, the archive is invalid.
Here's the code:
my $zip = Archive::Zip->new();
my $i;
foreach $i(#files)
{
my $fh = $zip->addFile("$directoryPath$i") if (-e "$directoryPath$i");
}
my $zipFilePath = "Test.zip";
die 'Cannot create $zip_file_name: $!\n' if $zip->writeToFileNamed("$zipFilePath") != AZ_OK;
open (DLFILE, "<$zipFilePath");
#fileholder = <DLFILE>;
close (DLFILE);
print "Content-Type:application/x-download\n";
print "Content-Disposition:attachment;filename=$zipFilePath\n\n";
print #fileholder;
Can you please tell me where the error is?
I am running the code using xampp on my local windows machine.
Edit: The same happens when I use
use strict;
use warnings;
use autodie;
Edit: The first problem is solved by ysth, thanks for that. Now the archive is not invalid after downloading, but still no files are shown if I open it, while the zip-file's size seems to be correct.

You are corrupting it here:
open (DLFILE, "<$zipFilePath");
#fileholder = <DLFILE>;
close (DLFILE);
by opening it such that it translates "\r\n" to just "\n".
Try this:
open( DLFILE, '<:raw', $zipFilePath );

Related

How to read a file which is gzipped and tar in perl

I have placed the text file "FilenameKeyword.txt" file in E:/Test folder, in my perl script i am trying to traverse through the folder and am i am trying to find a file with filename which has the string "Keyword" in it, later i have printed the content of that file in my script.
Now i wish do the same thing for the file which is placed inside tar file which is compressed.
Hypothetical File from where i am trying to extract the details:
E:\test.tar.gz
Wanted to know if there are possibility in perl to search and read the file without decompressing /unzipping the hypothetical file.If that is not possible, I shall also allocate some temperory memory to decompress the file , which should deleted after extracting the content from the particular text file.
While Searching in the internet i could it is possible to extract and read the gzip/tar file by using Archive::Extract, being new to Perl - i am really confused on how actually i should make use of it. Could you please help on this....
Input file:FilenameKeyword.txt
Script:
use warnings;
use strict;
my #dirs = ("E:\\Test\\");
my %seen;
while (my $pwd = shift #dirs) {
opendir(DIR,"$pwd") or die "Cannot open $pwd\n";
my #files = readdir(DIR);
closedir(DIR);
foreach my $file (#files)
{
if (-d $file and ($file !~ /^\.\.?$/) and !$seen{$file})
{
$seen{$file} = 1;
push #dirs, "$pwd/$file";
}
next if ($file !~ /Keyword/i);
my $mtime = (stat("$pwd/$file"))[9];
print "$pwd$file";
print "\n";
open (MYFILE, "$pwd$file");
while (my $line = <MYFILE>){
#print $line;
my ($date) = split(/,/,$line,2);
if ($line =~ s!<messageText>(.+?)</messageText>!!is){
print "$1";
}
}
}
}
Output(In test program file is placed under E:\Test):
E:\Test\FilenameKeyword.txt
1311 messages Picked from the Queue.
Looking for help to retrieve the content of the file which is place under
E:\test.tar.gz
Desired Output:
E:\test.tar.gz\FilenameKeyword.txt
1311 messages Picked from the Queue.
I was stuck in using CPAN module, CPAN module didn't work for me as i have oracle 10g enterprise edition in the same machine, due do some software conflict Active state perl was unable compile and refer to the perl lib for CPAN module, i have uninstalled oracle in my machine to make this work....
#!/usr/local/bin/perl
use Archive::Tar;
my $tar = Archive::Tar->new;
$tar->read("test.tar.gz");
$tar->extract();
If your file was gzipped only, you could read its contents in a "streamed" manner as outlined here (Piping to/from a child process without system or backtick - gzipped tar files). The article illustrates a technique to use open and a fork to open and decompress the file, and then making it available to Perl's while(), allowing you to iterate over it.
As tar is basically concatenating things, it might be possible to adapt this to your scenario.

Open file in perl and STDERR contents problems

I'm trying to write some unit tests for a perl file uploading script. I'm still pretty new to perl so I'm having some issues achieving the outcome I expect from my code.
Basically my thought process is that I can pass a test_only attribute along with the request that will tell the script to just grab a file already on the system rather than try to use an uploaded file.
I created a test file and put it in my output/tmp directory. I made sure to set its permissions to 775. Its just a simple .txt file that says "I am a test file".
What I expect to happen currently is that when I run my test script I should see the contents of the file printed out to the error log as well as some reference to the buffer(so I can verify the file is being opened properly). However, this is not happening, nothing is being put in the error log. I'm wondering if the file is being opened properly?
I'm sure I'm just missing something fundamental about how perl opens files. Any help will be appreciated. Thanks :)
This is the appropriate snippet of my code:
my $test_only = 1;
my $tmp_uploads_path = "/home/my_instance/output/tmp/";
if($test_only)
{
#put simulated file handle and file name here
$file = "";
$file_name = "test_file.txt";
}
else
{
$file = $q->upload('file')
|| die "No file data sent\n $!";
$file_name = $q->param('file_name')
|| die "No file_name sent\n $!";
}
########
#SAVE THE UPLOAD
########
my $bufsize = 1024;
my $buffer = '';
open(my $TMPFILE, ">".$tmp_uploads_path.$file_name);
binmode $TMPFILE;
print STDERR "=> ".Dumper($TMPFILE)."\n";
while(read ($TMPFILE, $buffer, $bufsize)){
print STDERR "=> ".Dumper($TMPFILE)."\n";
print STDERR "=> ".Dumper($buffer)."\n";
print $TMPFILE $buffer;
}
close($TMPFILE);
You opened the $TMPFILE for writing, due to the > mode. Therefore, you cannot read from it.
You should always put use strict; use warnings; at the top of your scripts, this would have alerted you to this problem!
You should open files like
my $name = ...;
open my $fh, "<", $name or die "Can't open $name: $!";
or
use autodie;
open my $fh, "<", $name;
That is, do proper error handling, and use the three-arg variant of open: handle, mode and name (don't concat mode and name, except on ancient perls).
I am also suprised that you are using read. You can get a similar effect by
local $/ = \$bufsize;
while (defined(my $buffer = <$TMPFILE>)) { ... }

Unable to open text file in Perl

I am fetching some log files (which are in txt format) from another server and trying to parse them using my Perl script. The logs are being fetched correctly after which I set permissions to 777 for the log directory.
After this I attempt to open the log files, one by one for parsing, via my Perl script. Now, the strange thing and the problem which happens is, my script is sometimes able to open the file and sometimes NOT. To put it simply, it's unable to open the log files for parsing at times.
Also, I have cronned this perl script and the chances of file open failing are greater when it runs via cron rather than manually, although they have run successfully in both cases previously. I don't understand where the issue lies.
Here is the code which I use for opening the files,
$inputDir = "/path/to/dir";
#inputFiles = <$inputDir/*>;
# inputFiles array is list of files in the log directory
foreach my $logFile(#inputFiles)
{
# just to ensure file name is text
$logFile = $logFile."";
# process file only if filename contains "NOK"
if(index($logFile,"NOK") > -1)
{
# opens the file
open($ifile, '<', $logFile) or die "Error: Unable to open file for processing.";
# file parsing takes place
}
}
close($ifile);
I want to re-iterate that this code HAS run successfully and I haven't changed any part of it. Yet, it does not run every time without fail, because its unable to open the log file at times. Any ideas?
You should include the error message $! and the file name $logFile in your die string to see why the open failed, and for which file.
open($ifile, '<', $logFile) or die "Error: Unable to open $logFile: $!";
Also, this line:
$logFile = $logFile."";
...is quite redundant. If a conversion is necessary, perl will handle it.
Just as an example, this is what you code should look like. You may like to try this version
use strict;
use warnings;
my $inputDir = '/path/to/dir';
my #inputFiles = <$inputDir/*>;
foreach my $logFile (grep /NOK/, #inputFiles) {
open my $ifile, '<', $logFile or die qq(Unable to open "$logFile": $!);
# Process data from <$ifile>;
}
Maybe opening some files fails, because your program has too many open files. Your program opens all files in $inputDir and processes them in the loop. After that it closes the last file opened.
EDIT: after reading TLP's comment and reading perldoc -f close and perldoc -f open I see that TLP is right and the filehandle in $ifile is closed by a subsequent open($ifile,'<',$logFile) . However, if the file parsing code not shown by the topic creator creates another reference to $ifile the file handle would stay open.
Moving the call to close into the if block should solve your problem:
$inputDir = "/path/to/dir";
#inputFiles = <$inputDir/*>;
# inputFiles array is list of files in the log directory
foreach my $logFile(#inputFiles)
{
# process file only if filename contains "NOK"
if(index($logFile,"NOK") > -1)
{
# opens the file
# added my to $ifile to keep local to this scope
open(my $ifile, '<', $logFile) or die "Error: Unable to open file for processing.";
# file parsing takes place
# close current file
close($ifile);
}
}

Perl Programm keep waiting to open a file using utf8

I am trying to read a UTF-8 encoded xml file. This file is of size around 8M and contains only one line.
I used below line to open this single line xml file:
open(INP,"<:utf8","$infile") or die "Couldn't open file passed as input, $!";
local $/ = undef;
my $inputfile = <INP>;
print $inputfile; ## Not working..
But after this line program get stuck and keep waiting.
I have tried other methods like binmode and decode but getting the same issue.
The same Program works when i change above mentioned file opening code to:
open(INP,"$infile") or die "Couldn't open file passed as input, $!";
local $/ = undef;
my $inputfile = <INP>;
print $inputfile; ## It works..
open(INP,"$infile") or die "Couldn't open file passed as input, $!";
binmode(INP, ":utf8");
local $/ = undef;
my $inputfile = <INP>;
print $inputfile; ## Not working..
Can you please help me what I am doing wrong here? I need to perform some operation on the input data and have to get utf8 encoded output.
I tried your last snippet here (Ubuntu 12.04, perl 5.14.2) and it works as expected. Only problem I have, is a difference between the input and output. Input file is UTF-8 and output is ISO-8859-1.
When I add
use utf8;
use open qw(:std :utf8);
this problem is gone, though. So this must be an environment issue.

Perl to set a directory to open, open it, then print the directory opened?

Trying to troubleshoot a port of some perl code from CentOS to Windows.
Really know nothing about Perl, and the code I'm porting is around 700-1000 lines. 100% sure one of the issues I'm seeing is related to how the code is being rendered as a result of being on the OS it's running on.
So, I'm looking for a way to troubleshoot debugging how the OS's are rendering filepath apart from the legacy code; which I can not post to SO due to "IP" reasons.
So, I looking for some perl that I can set a directory to open within the script (for example, C:\data\ or /home/data), then script attempts to load the directory, prints if it failed or succeeded, and then prints the string it attempted to load, regardless if the code failed to open the directory or not.
Open to suggestions, but that's the issue, and the solution I'm seeing.
Questions, feedback, requests - just comment, thanks!!
use IO::Dir;
my $dir = IO::Dir->new($dir_path) or
die "Could not open directory $dir_path: $!\n";
of course, where $dir_path is some path to a directory on your system that you want, either as a var or hard coded. The more 'old school' way would look like:
opendir my $dir, $dir_path or die "Could not open directory $dir_path: $!\n";
That won't print of the directory is opened, but the program will fail if it doesn't open it then print the precise error as to why, which is what the $! variable holds.
Is this what you're looking for?
use DirHandle;
my $dir = "test";
my $dh = new DirHandle($dir);
if($dh) {
print "open directory succeeded\n";
}
else {
print "open directory failed\n";
}
print $dir, "\n";
new DirHandle opens the directory and returns a handle to it. The handle will be undef if the open failed.