È necessario leggere ogni singolo byte per verificare se un file copiato è identico all'originale?


16

Di recente ho appreso di un programma chiamato Total Commander. È un sostituto di Windows Explorer e ha le sue cose per copiare i file. Per verificare se i file sono identici, anziché calcolare un CRC, controlla letteralmente ogni singolo byte, uno alla volta, sia sull'originale che sulla copia.

La mia domanda è: è necessario? CRC o qualsiasi altra tecnica del genere può andare storto? Come programmatore, dovresti provare a implementare questo sistema perfetto ma lento, o è troppo estremo?


3
Dai un'occhiata a come "rsync" gestisce questo.

21
Il calcolo dei CRC (o, meglio, sha1sums) su entrambi i file richiede comunque la lettura di ogni byte. Se fai un confronto byte per byte, puoi uscire non appena vedi una mancata corrispondenza - e non devi preoccuparti di due file diversi che hanno lo stesso checksum (anche se è incredibilmente improbabile per sha1sum) . D'altra parte, i confronti di checksum sono utili quando si confrontano file che non si trovano sulla stessa macchina; i checksum possono essere calcolati localmente e non è necessario trasferire l'intero contenuto sulla rete.
Keith Thompson,

3
Per quanto riguarda la probabilità di collisione, se usi un hash decente come sha1sumte praticamente non devi preoccupartene, a meno che qualcuno non stia costruendo deliberatamente ed economicamente file i cui sha1sums si scontrano. Non ho una fonte per questo, ma ho sentito (nel contesto di git) che la probabilità che due file diversi abbiano lo stesso sha1sum è quasi uguale alla probabilità che ogni membro del tuo team di sviluppo venga mangiato da lupi. Lo stesso giorno. In incidenti completamente non correlati.
Keith Thompson,

5
@KeithThompson: Penso che il tuo primo commento dovrebbe essere una risposta :-)
Dean Harding,

6
Risposta breve - No, è meglio che il tuo computer lo faccia per te.
psr

Risposte:


40

Il calcolo dei CRC (o, meglio, sha1sums) su entrambi i file richiede comunque la lettura di ogni byte. Se fai un confronto byte per byte, puoi uscire non appena vedi una mancata corrispondenza - e non devi preoccuparti di due file diversi che hanno lo stesso checksum (anche se è incredibilmente improbabile per sha1sum) . Quindi, se stai facendo il confronto localmente, un confronto byte per byte sarà almeno altrettanto veloce di un confronto checksum (a meno che tu non abbia già calcolato i checksum comunque).

D'altra parte, i confronti di checksum sono utili quando si confrontano file che non si trovano sulla stessa macchina; i checksum possono essere calcolati localmente e non è necessario trasferire l'intero contenuto sulla rete.

Sono anche possibili approcci ibridi. Ad esempio, è possibile calcolare e confrontare i checksum per i due file un pezzo alla volta, il che può evitare di leggere tutti i file ( se differiscono) evitando anche di trasmettere l'intero file attraverso la rete. Il protocollo rsync fa qualcosa del genere.

Nota che l'uso di un semplice CRC ti dà una buona probabilità di una collisione, come menzionato da Dave Rager nella sua risposta. Usa almeno sha1sum o anche qualcosa di più recente. (Non tentare di inventare il tuo algoritmo di hashing; le persone che hanno sviluppato sha1sum sanno molto di più su queste cose rispetto a nessuno dei due.)

Per quanto riguarda la probabilità di collisione, se usi un hash decente come sha1sum non devi preoccuparti, a meno che qualcuno non stia costruendo deliberatamente ed economicamente file i cui sha1sums si scontrano (generare tali collisioni non era fattibile quando l'ho scritto per la prima volta , ma si stanno compiendo progressi ). Citando "Pro Git" di Scott Chacon , sezione 6.1 :

Ecco un esempio per darti un'idea di cosa sarebbe necessario per ottenere una collisione SHA-1. Se tutti i 6,5 miliardi di umani sulla Terra stessero programmando, e ogni secondo, ognuno produceva codice che era l'equivalente dell'intera storia del kernel Linux (1 milione di oggetti Git) e lo spingeva in un enorme repository Git, ci sarebbero voluti 5 anni quel repository conteneva abbastanza oggetti da avere una probabilità del 50% di una singola collisione di oggetti SHA-1. Esiste una maggiore probabilità che ogni membro del team di programmazione venga attaccato e ucciso dai lupi in incidenti non collegati nella stessa notte.

Sommario :

Il confronto byte per byte è utile per i confronti locali. sha1sum è buono per il confronto remoto e non presenta possibilità significative di falsi positivi.


Va notato che la definizione comune di una funzione hash "buona" include la proprietà che è molto difficile creare input diversi con lo stesso hash ("resistenza alla collisione"). SHA-1 ha alcuni (finora teorici) punti deboli in questo senso, ma non puoi semplicemente "costruire due file che si scontrano", anche se ci provi abbastanza.
sleske,

@sleske: Aggiornato
Keith Thompson,

1
@KeithThompson Sto votando la risposta, ma penso che sia giunto il momento di un aggiornamento su SHA1 - The SHAppening
K.Steff

Sospetto che diventerebbero irritabili se provassi a ospitare questo repository teorico su GitHub.
hBy2Py,

1
Intendevo più dire che sarebbero stati infelici se avessero comunque molti exabyte al secondo di dati. :-)
hBy2Py

10

Ecco un altro modo di pensarci.

Se non è possibile che due file diversi abbiano lo stesso CRC, allora per estensione significa che ogni file può essere rappresentato da un CRC univoco.Se il CRC era più piccolo del file originale, rappresenterebbe una forma di compressione senza perdita. In caso contrario, faresti altrettanto per confrontare i file originali dal momento che dovresti confrontare lo stesso numero di byte.

In teoria potresti usare la compressione senza perdita di dati di entrambi i lati del confronto per ridurre il numero di byte necessari nel confronto, ma è una folle commissione perché sprecheresti più cicli e dovresti leggere ogni byte di entrambi i file per fare la compressione . Cioè, per codificare ogni byte (e il suo ordine) in uno schema di compressione senza perdita dovresti prima leggerlo e collegarlo all'algoritmo, giusto? Gioco finito.

Ecco un'analogia:
se volevi un modo per determinare rapidamente se due documenti stampati fossero identici senza confrontare lettere per lettere, potresti confrontare il conteggio delle lettere su ciascuna riga dei documenti. Se i conteggi corrispondessero tutti, le probabilità migliorerebbero sostanzialmente che i documenti fossero identici, tuttavia nessuno sosterrebbe che potresti essere certo che ogni lettera fosse la stessa usando questo approccio.


3

L'unico modo perfetto per verificare la presenza di file identici è il confronto byte per byte. Un altro modo per essere una buona approssimazione è calcolare un hash come MD5 per i file e confrontarli. È possibile che ci sia una collisione tra hash ma non molto probabilmente.

Immagino che il byte per il confronto dei byte sia più veloce rispetto al calcolo dell'hash su entrambi i file nel momento in cui si esegue il confronto. Tuttavia, se l'applicazione calcola pre-calcolo dell'hash e memorizza i metadati relativi ai file, il confronto degli hash sarà notevolmente più rapido.

CRC probabilmente non è la strada da percorrere in quanto è solo un meccanismo di rilevamento degli errori, non un hash. (o un hash scadente con molte possibili collisioni)


+1 Accetto. È molto più probabile che il tuo disco rigido si rompa rispetto alla collisione accidentale di una buona funzione di hashing (CRC32 è debole - anche d'accordo).
Michał Šrajer,

2

Per essere certi che due file siano identici al 100%, devi davvero controllare i byte.

Perché? Hash collisioni, ecco perché! A seconda dell'algoritmo utilizzato per l'hash, la collisione potrebbe essere più o meno probabile, ma è possibile comunque. Seguendo questi passaggi:

  1. Controlla le dimensioni dei file
  2. Controlla i tipi di mime
  3. Controlla l'hash
  4. Controlla alcuni offset casuali e confronta i bit

Ti garantirà una certezza molto alta che i due file sono uguali, tuttavia c'è una possibilità (estremamente) minima di avere una collisione tra le mani. La scelta di quanto lontano vuoi andare con i tuoi confronti sarà dettata dalla situazione.


Penso che se scegli un buon algoritmo di hashing, il 2. e 4. non ti daranno un reale aumento della qualità "uguale". Probabilmente 1. è necessario solo per l'hash debole.
Michał Šrajer,

1
-1 Questo non ha senso. Se scegli un buon algoritmo di hashing, tutti gli altri passaggi sono superflui. 1. e 4. in realtà sono già coperti da ciò che fa un hash, e 2. è una sciocchezza (la maggior parte dei file system non ha nemmeno una nozione di "tipo MIME" e, anche se avesse, aggiunge pochissime informazioni).
sleske,

@sleske Sto dicendo invece di eseguire l'hashing del file, che è un'operazione intensiva, è possibile eseguire alcune operazioni preliminari che non sono così pesanti.

Riconosco solo 1 e 3 ha molto senso. (1) segnalerà la maggior parte dei casi di file diversi salvando la necessità di calcolare l'hash. Lo scontro hash sullo stesso file di lunghezza è così improbabile che non vale la pena preoccuparsi.
Michael Shaw,

1

Come altri hanno già detto, è più veloce fare un confronto byte per byte se i due file si trovano sullo stesso sistema. Se stai cercando di confrontare un gruppo di file, raggiungerai il punto in cui l'hash è la risposta migliore se i file si trovano nella memoria rotante.

L'hashing brilla davvero quando non hai tutti i dati prontamente disponibili. Ad esempio, i file si trovano su macchine diverse. Inoltre, consente di salvare i risultati dei calcoli e di consultarli in un secondo momento. (Questo rapporto è uguale a quello precedente? Quando fai il rapporto salvane un hash. Quando fai il prossimo puoi semplicemente confrontare gli hash. Non solo non devi leggere quello vecchio in te don ' ho anche bisogno di averne una copia disponibile.)


0

Penso che dovresti usare l'utilità di confronto dei file fornita con il tuo sistema operativo o utilizzare uno strumento di confronto dei file (vedi: strumenti di confronto di wiki-file ) per confrontare i contenuti DOPO aver verificato le proprietà dei file delineate da @Glenn Nelson.

Non credo che CRC sia preciso al 100% e penso che la sua precisione diminuisca con la lunghezza del file. Inoltre, non consiglio di scriverlo da zero poiché potrebbe richiedere molti test.


0

È necessario leggere ogni singolo byte per verificare se un file copiato è identico all'originale? SÌ per essere sicuro al 100%

È necessario leggere ogni singolo byte per verificare se un file copiato NON è identico all'originale? NO

Pertanto, per determinare rapidamente la non-identicità, controllare innanzitutto i metadati come la dimensione del file e qualsiasi tipo di checksum / CRC o MIME che il sistema operativo / file system / archivio potrebbe già mantenere . Poiché sono pre-calcolati da quel sistema, non si paga questo costo al momento del confronto.

Se il test ha esito positivo, devi comunque confrontare ogni singolo byte se devi essere sicuro al 100%, MA NOTA che nelle moderne CPU pipeline, e usando più thread e possibilmente più processori / CPU, fare un confronto a blocchi di file di grandi dimensioni è DAVVERO veloce ed efficiente perché il processo è altamente parallelizzabile. Molto più veloce di QUALSIASI tipo di calcolo matematico che coinvolge ogni byte (anche se alcuni algoritmi sono forse anche parallelizzabili, ma forse non così facilmente o così bene). Questo perché le CPU pipeline possono eseguire operazioni di confronto a blocchi della memoria in microcodice o persino hardware (molto velocemente) e sottosistemi da disco a memoria sono altamente ottimizzati per portare enormi blocchi di file nella / dalla memoria, tutti eseguiti in parallelo e con hardware. Se la tua applicazione fa questo genere di cose regolarmente, ed è un collo di bottiglia delle prestazioni noto, sarebbe saggio implementarlo in codice multithread ben scritto che sfrutta le funzionalità di parallelismo del tuo sistema operativo e hardware (forse usa un linguaggio progettato per Questo).

Solo se desideri elaborare ogni file una volta e fare più confronti in un secondo momento (dove ricordi ["cache"] il risultato dell'analisi riepilogata o "compressa" [come dice JohnFX]), ci sarà un vantaggio significativo nel farlo, e anche allora, solo per dimostrare la differenza (probabile); per dimostrare l'identità, dovresti comunque fare il confronto byte per byte.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.