tags:

views:

130

answers:

5

To my perl script, a file is passed as an arguement. The file can be a .txt file or a .zip file containing the .txt file.

I want to write code that looks something like this

if ($file is a zip) {

    unzip $file
    $file =~ s/zip$/txt/;
}

One way to check the extension is to do a split on . and then match the last result in the array (returned by split).

Is there some better way?

+4  A: 

How about checking the end of the filename?

if ($file =~ /\.zip$/i) {

and then:

use strict;
use Archive::Extract;

if ($file =~ /\.zip$/i) {
    my $ae = Archive::Extract->new(archive => $file);
    my $ok = $ae->extract();
    my $files = $ae->files();
}

more information here.

eumiro
+1  A: 

You can check the file extension using a regex match as:

if($file =~ /\.zip$/i) {
        # $file is a zip file 
}
codaddict
+1  A: 

Why rely on file extension? Just try to unzip and use appropriate exception handling:

eval {
    # try to unzip the file
};

if ($@) {
    # not a zip file
}
eugene y
What if you don't have 'unzip' installed on your system, or if it is not in your path?
Prakash K
@Prakash: `unzip` is supposed to be a perl function. Nevermind, replaced with comments :)
eugene y
+9  A: 

Another solution is to make use of File::Type which determines the type of binary file.

use strict;
use warnings;

use File::Type;

my $file      = '/path/to/file.ext';
my $ft        = File::Type->new();
my $file_type = $ft->mime_type($file);

if ( $file_type eq 'application/octet-stream' ) {
    # possibly a text file
}
elsif ( $file_type eq 'application/zip' ) {
    # file is a zip archive
}

This way, you do not have to deal with missing/wrong extensions.

Alan Haggai Alavi
+1, but you should replace `my $file_type = File::Type->mime_type($file);` by `my $file_type = $ft->mime_type($file);`
M42
Thanks for pointing that out.
Alan Haggai Alavi
`File::Type` works here, but in general does a pretty crappy job compared to [`File::LibMagic`](http://p3rl.org/File::LibMagic).
daxim
This is probably the best approach (either module) but the -T file test operator might be worth looking at too.
Nic Gibson
daxim: I will try `File::LibMagic`. Thank you.
Alan Haggai Alavi
+4  A: 

You can use File::Basename for this.

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

use File::Basename;

my @exts = qw(.txt .zip);

while (my $file = <DATA>) {
  chomp $file;
  my ($dir, $name, $ext) = fileparse($file, @exts);

  given ($ext) {
    when ('.txt') {
      say "$file is a text file";
    }
    when ('.zip') {
      say "$file is a zip file";
    }
    default {
      say "$file is an unknown file type";
    }
  }
}

__DATA__
file.txt
file.zip
file.pl

Running this gives:

$ ./files 
file.txt is a text file
file.zip is a zip file
file.pl is an unknown file type
davorg