2010-10-15 15 views
7

Do mojego skryptu perl plik jest przekazywany jako argument. Plik może być plikiem .txt lub plikiem .zip zawierającym plik .txt.Jak mogę sprawdzić rozszerzenie pliku za pomocą Perla?

Chcę napisać kod, który wygląda mniej więcej tak

if ($file is a zip) { 

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

Jeden ze sposobów sprawdzenia rozszerzenie jest zrobić podział na . a następnie dopasować ostatni wynik w tablicy (zwrócony przez split).

Czy jest jakiś lepszy sposób?

+8

Czy na pewno chcesz sprawdzić rozszerzenie? Jeśli masz nadzieję przetestować, z którym typem pliku masz do czynienia, lepiej byłoby sprawdzić typ MIME. Spójrz na coś takiego: http://search.cpan.org/~pmison/File-Type-0.22/lib/File/Type.pm – totels

+0

Chiming z obsługą @totels i kilkoma odpowiedziami niższego przedstawiciela . Jestem zaskoczony, jak wielu myślących, że poleganie na rozszerzeniu jest bezpieczne ('mv virus.exe hooters.jpg') lub solidne (' mv some-huge-dossy-garbage.bin whatever.zip'). Zakładając, że zip i błędy przechwytywania lub odkrywania typu MIME są właściwe odpowiedzi. Każde rozwiązanie wykorzystujące rozszerzenie jest błędem. – Ashley

Odpowiedz

11

Możesz użyć File :: Basename do tego.

#!/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 ($name, $dir, $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 to daje:

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

'fileparse' zwraca najpierw nazwę pliku, a nie katalog. –

+0

Masz rację, oczywiście, i naprawiłem to. Dziwne, że przeszło niezauważone przez ponad pięć lat. Dziękuję za wskazanie. –

+0

Bez obaw, Twój post rozwiązał mój problem po uporządkowaniu zamówienia :) –

6

Co powiesz na sprawdzenie końca nazwy pliku?

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

, a następnie:

use strict; 
use Archive::Extract; 

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

więcej informacji here.

2

Można sprawdzić rozszerzenia pliku przy użyciu regex mecz jak:

if($file =~ /\.zip$/i) { 
     # $file is a zip file 
} 
2

Dlaczego polegać na rozszerzenie pliku? Wystarczy spróbować rozpakować i używać odpowiednią obsługę wyjątków:

eval { 
    # try to unzip the file 
}; 

if ([email protected]) { 
    # not a zip file 
} 
+0

Co zrobić, jeśli nie masz zainstalowanego "unzip" w systemie lub nie ma go na swojej ścieżce? –

+0

@Prakash: 'unzip' ma być funkcją perla.Nieważne, zastąpione komentarzami :) –

12

Innym rozwiązaniem jest wykorzystanie File::Type który określa typ pliku binarnego.

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 
} 

W ten sposób nie musisz radzić sobie z brakującymi/błędnymi rozszerzeniami.

+1

+1, ale powinieneś zamienić 'my $ file_type = Plik :: Typ-> mime_type ($ file);' według 'my $ file_type = $ ft-> mime_type ($ file);' – Toto

+0

Dzięki za wskazanie tego. –

+2

"Plik :: Typ" działa tutaj, ale generalnie robi całkiem nieudaną pracę w porównaniu do ['Plik :: LibMagic'] (http://p3rl.org/File::LibMagic). – daxim

1

Wiem, że to pytanie jest kilka lat, ale dla każdego, kto przychodzi tu w przyszłości, łatwym sposobem rozpadają ścieżkę pliku do jego składowej ścieżki nazwa pliku, nazwa serwisu i rozszerzenie są następujące.

use File::Basename; 

my $filepath = '/foo/bar.txt'; 

my ($basename, $parentdir, $extension) = fileparse($filepath, qr/\.[^.]*$/); 
my $filename = $basename . $extension; 

Możesz przetestować jego wyniki, wykonując następujące czynności.

my @test_paths = (
    '/foo/bar/fish.wibble', 
    '/foo/bar/fish.', 
    '/foo/bar/fish.asdf.d', 
    '/foo/bar/fish.wibble.', 
    '/fish.wibble', 
    'fish.wibble', 
); 

foreach my $this_path (@test_paths) { 
    print "Current path: $this_path\n"; 
    my ($this_basename, $parentdir, $extension) = fileparse($this_path, qr/\.[^.]*$/); 
    my $this_filename = $this_basename . $extension; 

    foreach my $var (qw/$parentdir $this_filename $this_basename $extension/) { 
     print "$var = '" . eval($var) . "'\n"; 
    } 

    print "\n\n"; 
} 

Mam nadzieję, że to pomoże.

Powiązane problemy