2010-05-17 7 views
13

Questa domanda deriva dalla necessità di garantire che le modifiche apportate al codice non influiscano sui valori che emette sul file di testo. Idealmente, farei un sottotitolo per prendere due nomi di file e return 1 o return 0 a seconda che i contenuti siano identici o meno, gli spazi bianchi e tutto il resto.Come posso usare Perl per determinare se il contenuto di due file è identico?

Dato che l'elaborazione del testo è un bene di Perl, dovrebbe essere abbastanza facile confrontare due file e determinare se sono identici o meno (codice sotto non testato).

use strict; 
use warnings; 

sub files_match { 

    my ($fileA, $fileB) = @_; 
    open my $file1, '<', $fileA; 
    open my $file2, '<', $fileB; 

    while (my $lineA = <$file1>) { 

     next if $lineA eq <$file2>; 
     return 0 and last; 
    } 

    return 1; 
} 

L'unico modo che posso pensare (sans moduli CPAN) è quello di aprire i due file in questione, e leggerli in linea per linea fino a quando viene trovata una differenza. Se non viene rilevata alcuna differenza, i file devono essere identici.

Ma questo approccio è limitato e impacciato. Cosa succede se le linee totali differiscono nei due file? Devo aprire e chiudere per determinare il conteggio delle righe, quindi riaprire per eseguire la scansione dei testi? Che schifo.

Non vedo nulla in perlfaq5 relativo a questo. Voglio stare lontano dai moduli a meno che non vengano con la distribuzione core Perl 5.6.1.

+0

Sono sorpreso che questa domanda non sia comparsa su SO prima. – Zaid

+1

perché non usare diff? - Se sei su * nix – heferav

+0

@heferav: Renderizza a Perl ciò che può gestire abilmente. Non ho davvero fatto molto in termini di programmazione Unix, tutto qui;) – Zaid

risposta

28

È nel core.

use File::Compare; 

if (compare("file1", "file2") == 0) { 
    print "They're equal\n"; 
} 
+0

Whew! Sapevo che sarebbe stato qualcosa di semplice. – Zaid

+0

'File :: Compare' equivale approssimativamente ad aprire i file e leggerli riga per riga (o, se si utilizza il terzo argomento, blocco per blocco). Se sei preoccupato per le prestazioni, potresti voler controllare le dimensioni del file e i numeri di inode prima di chiamarlo. –

+0

In realtà File :: Confronta controlla già la dimensione del file. Controlla la fonte http://cpan.uwinnipeg.ca/htdocs/perl/File/Compare.pm.html –

7

Ci sono un paio di controlli O (1) che è possibile fare prima per vedere se i file sono diversi.

Se i file hanno dimensioni diverse, sono ovviamente diversi. La funzione stat restituirà le dimensioni dei file. Restituirà anche un altro dato che sarà utile: il numero di inode. Se i due file sono in realtà lo stesso file (poiché è stato passato lo stesso nome file per entrambi i file o perché entrambi i nomi sono hardlink per lo stesso file), il numero di inode sarà lo stesso. Un file è ovviamente uguale a se stesso. Mettendo da parte questi due controlli, non esiste un modo migliore per confrontare due file locali per l'equivalenza, se non per confrontarli direttamente l'uno con l'altro. Naturalmente, non è necessario farlo riga per riga, se lo desideri puoi leggere in blocchi più grandi.

#!/usr/bin/perl 

use strict; 
use warnings; 

use File::Compare(); 

sub compare { 
    my ($first, $second)    = @_; 
    my ($first_inode, $first_size) = (stat $first)[1, 7]; 
    my ($second_inode, $second_size) = (stat $second)[1, 7]; 

    #same file, so must be the same; 
    return 0 if $first_inode == $second_inode; 

    #different sizes, so must be different 
    return 1 unless $first_size == $second_size; 

    return File::Compare::compare @_; 
} 

print compare(@ARGV) ? "not the " : "", "same\n"; 
+0

La domanda è nel contesto di un linguaggio di scripting portatile (Perl). Questa risposta è specifica del sistema operativo e del file system. L'ipotesi che gli inode siano unici e comparabili fallirà notevolmente su Windows (tutti i filesystem) e anche su file system orientati ai blocchi su UNIX, fallirà per gli inode su diversi volumi, partizioni, sottovolumi ecc. – Garen

Problemi correlati