2015-02-19 41 views
7

Su un file system senza distinzione tra maiuscole e minuscole, come NTFS o HFS +, dato il nome di un file, qual è il modo più efficiente per determinare la versione del nome file conservata in maiuscolo?Come trovare il nome di un file conservato in maiuscolo in Perl?

Considerare il HFS + (Mac OS X):

> perl -E 'say "yes" if -e "/TMP"' 
yes 

Si dice che esiste, naturalmente, ma non ho idea di come il suo caso è conservato. Qual è il modo più efficace per determinare il caso reale?

Quello che ho provato finora:

  • glob con classi di personaggi: Non funziona su Windows:

    > perl -E "say for glob "C:\\Perl" 
    C:\Perl 
    > perl -E "say for glob "C:\\[Pp][Ee][Rr][Ll]" 
    

    nota la mancanza di uscita da quella dell'ultimo comando. :-(

  • opendir/readdir: Works, ma sembra piuttosto inefficiente per leggere un'intera directory:

    > perl -E "opendir my $dh, 'C:\\'; say for grep { lc $_ eq 'perl' } readdir $dh; close $dh" 
    Perl 
    

E 'pazzesco pensare che non ci dovrebbero essere alcune istruzioni del sistema operativo di base o qualcosa per ottenere queste informazioni in modo più efficiente?

+0

Questa domanda potrebbe aiutare per HFS +: http://stackoverflow.com/a/13544447/702638 –

risposta

4

La soluzione opendir/readdir/grep è quella giusta. Via Twitter, Neil Bowers punti a questa citazione da perlport:

non contare su filename globbing. Utilizzare invece opendir, readdir e closedir.

@miyagawa, anche via Twitter, afferma che non v'è alcuna chiamata di sistema per questo, e se ci fosse, non sarebbe portatile.

E dato che @mob's answer e commenti from David Golden suggeriscono che glob sarebbe più costoso di opendir, readdir, in ogni caso, non vi sembra che sia nessun altro modo intorno ad esso.

Quindi, ecco la funzione che ho scritto per trovare tutti i casi per un determinato nome di base in una directory:

sub _actual_filenames { 
    my $dir = shift; 
    my $fn = lc shift; 
    opendir my $dh, $dir or return; 
    return map { File::Spec->catdir($dir, $_) } 
     grep { lc $_ eq $fn } readdir $dh; 
} 
+1

Errore per 'C: \ PROGRA ~ 1' su Windows. Per lo meno, dovrebbe restituire 'C: \ PROGRA ~ 1', ma' C: \ Program Files' sarebbe di gran lunga migliore. – ikegami

2

La funzione glob non riconosce le classi di caratteri stile di espressione regolare ([Pp], [Ee]). Invece utilizzaEspansione dei caratteri jolly in stile. Per compiere il proprio compito esempio, che ci si vuole usare la sintassi

glob("C:\\{P,p}{E,e}{R,r}{L,l}") 

Non conosco i dettagli di implementazione di glob, ma sembra che sarebbe anche necessario esaminare tutti i file in una directory, e sarebbe non necessariamente essere più efficiente del tuo linguaggio readdir/grep.

O, più conciso (ancora una volta, non necessariamente in modo più efficiente), un glob/grep linguaggio:

perl -E "say for grep {/C:\\PERL/i} glob('C:\*')" 

(aggiornato, ancora non testato)

+0

Stranamente, su Windows che emette: 'C: {P, p} ERl C: {P, p} ERL C: {P, p} Erl C: {P, p} ErL C: {P, p } ERL C: {P, p} ERL C: {P, p} Erl C: {P, p} ERL ' – theory

+0

Inoltre non gestisce' C: \ PROGRA ~ 1' – ikegami

4

In Windows,

>perl -MWin32 -E"say Win32::GetLongPathName($ARGV[0])" "C:\PROGRAM FILES" 
C:\Program Files 

>perl -MWin32 -E"say Win32::GetLongPathName($ARGV[0])" C:\PROGRA~1 
C:\Program Files 

Su Unix , La funzione F_GETPATH di fcntl verrà eseguita.

+0

non portatile, ala S. – theory

+0

Già aggiunto una soluzione unix. – ikegami

+0

"F_GETPATH" non viene esportato dal modulo Fcntl – theory