É necessário ler todos os bytes para verificar se um arquivo copiado é idêntico ao original?

16

Eu aprendi recentemente de um programa chamado Total Commander. É uma substituição do Windows Explorer e tem seu próprio material para copiar arquivos. Para verificar se os arquivos são idênticos, em vez de calcular um CRC, ele literalmente verifica cada byte, um de cada vez, no original e na cópia.

Minha pergunta é: isso é necessário? A CRC ou qualquer outra técnica desse tipo pode dar errado? Como programador, você deve tentar implementar esse sistema perfeito, mas lento, ou é muito extremo?

Koen027
fonte
3
Veja como o "rsync" lida com isso.
21
O cálculo de CRCs (ou, melhor, sha1sums) nos dois arquivos requer a leitura de todos os bytes. Se você fizer uma comparação de byte a byte, poderá sair assim que encontrar uma incompatibilidade - e não precisará se preocupar com dois arquivos diferentes que possuam a mesma soma de verificação (embora isso seja improvável para sha1sum) . Por outro lado, as comparações de soma de verificação são úteis quando você está comparando arquivos que não estão na mesma máquina; as somas de verificação podem ser calculadas localmente e você não precisa transferir todo o conteúdo pela rede.
perfil completo de Keith Thompson
3
Quanto à probabilidade de colisão, se você usa um hash decente como sha1sumvocê, não precisa se preocupar com isso, a menos que alguém esteja deliberada e dispendiosamente construindo arquivos cujos sha1sums colidem. Eu não tenho uma fonte para isso, mas ouvi (no contexto do git) que a probabilidade de dois arquivos diferentes terem o mesmo sha1sum é quase a mesma que a probabilidade de cada membro de sua equipe de desenvolvimento ser comido por Lobos. No mesmo dia. Em incidentes completamente não relacionados.
Keith Thompson
5
@KeithThompson: Eu acho que o seu primeiro comentário deve ser uma resposta :-)
Dean Harding
6
Resposta curta - Não, é melhor que seu computador faça isso por você.
Psr

Respostas:

40

O cálculo de CRCs (ou, melhor, sha1sums) nos dois arquivos requer a leitura de todos os bytes. Se você fizer uma comparação de byte a byte, poderá sair assim que encontrar uma incompatibilidade - e não precisará se preocupar com dois arquivos diferentes que possuam a mesma soma de verificação (embora isso seja improvável para sha1sum) . Portanto, se você estiver fazendo a comparação localmente, uma comparação de byte a byte será pelo menos tão rápida quanto uma comparação de soma de verificação (a menos que você já tenha calculado as somas de verificação de qualquer maneira).

Por outro lado, as comparações de soma de verificação são úteis quando você está comparando arquivos que não estão na mesma máquina; as somas de verificação podem ser calculadas localmente e você não precisa transferir todo o conteúdo pela rede.

Abordagens híbridas também são possíveis. Por exemplo, você pode calcular e comparar somas de verificação para os dois arquivos um pedaço de cada vez, o que pode evitar a leitura dos arquivos inteiros ( se eles diferirem) e também a transmissão do arquivo inteiro pela rede. O protocolo rsync faz algo assim.

Observe que o uso de um CRC simples oferece uma boa chance de colisão, como Dave Rager mencionou em sua resposta. Use pelo menos sha1sum ou mesmo algo mais recente. (Não tente inventar seu próprio algoritmo de hash; as pessoas que desenvolveram sha1sum sabem muito mais sobre isso do que qualquer um de nós.)

Quanto à probabilidade de colisão, se você usa um hash decente como sha1sum, não precisa se preocupar com isso, a menos que alguém esteja construindo deliberada e dispendiosamente arquivos cujos sha1sums colidem (gerar essas colisões não era viável quando escrevi pela primeira vez isso. , mas está sendo feito progresso ). Citando o "Pro Git" de Scott Chacon , seção 6.1 :

Aqui está um exemplo para lhe dar uma idéia do que seria necessário para obter uma colisão com SHA-1. Se todos os 6,5 bilhões de humanos na Terra estivessem programando, e a cada segundo, cada um estivesse produzindo código equivalente a toda a história do kernel do Linux (1 milhão de objetos Git) e inserindo-o em um enorme repositório Git, levaria 5 anos até esse repositório continha objetos suficientes para ter uma probabilidade de 50% de uma única colisão de objeto SHA-1. Existe uma probabilidade maior de que todos os membros da sua equipe de programação sejam atacados e mortos por lobos em incidentes não relacionados na mesma noite.

Resumo:

A comparação byte a byte é boa para comparações locais. O sha1sum é bom para comparação remota e não apresenta chance significativa de falsos positivos.

Keith Thompson
fonte
Deve-se notar que a definição comum de uma função de hash "boa" inclui a propriedade de que é muito difícil criar entradas diferentes com o mesmo hash ("resistência a colisões"). O SHA-1 tem algumas fraquezas (até agora teóricas) a esse respeito, mas você não pode simplesmente "construir dois arquivos que colidem", mesmo se você se esforçar bastante.
sleske
@sleske: Atualizado
Keith Thompson
1
@KeithThompson Estou votando positivamente na resposta, mas acho que está na hora de atualizar o SHA1 - The SHAppening
K.Steff 16/16
Eu suspeito que eles ficariam irritados se você tentasse hospedar esse repositório teórico no GitHub.
Hby2Py 18/10/2016
1
Eu quis dizer mais que eles ficariam descontentes por ter, no entanto, muitos exabytes por segundo de dados enviados a eles. :-)
hBy2Py 18/10
10

Aqui está outra maneira de pensar sobre isso.

Se não houver possibilidade de que dois arquivos diferentes tenham o mesmo CRC, por extensão, significa que cada arquivo pode ser representado por um único CRC. Se o CRC for menor que o arquivo original, isso representará uma forma de compactação sem perdas. Caso contrário, você faria o mesmo para comparar os arquivos originais, pois compararia o mesmo número de bytes.

Em teoria, você poderia usar a compactação sem perdas de ambos os lados da comparação para reduzir o número de bytes necessários na comparação, mas é uma tarefa tola, porque você gastaria mais ciclos e teria que ler todos os bytes dos dois arquivos para fazer a compactação . Ou seja, para codificar cada byte (e sua ordem) em um esquema de compactação sem perdas, é necessário primeiro lê-lo e conectá-lo ao algoritmo, certo? Fim de jogo.

Aqui está uma analogia:
se você quisesse determinar rapidamente se dois documentos impressos eram idênticos sem comparar letra por letra, você poderia comparar a contagem de letras em cada linha dos documentos. Se todas as contagens corresponderem, as chances aumentam substancialmente de que os documentos sejam idênticos; no entanto, ninguém argumentaria que você poderia ter certeza de que todas as letras eram iguais usando essa abordagem.

JohnFx
fonte
3

A única maneira perfeita de verificar arquivos idênticos é o byte para comparação de bytes. Outra maneira de ser uma aproximação justa é calcular um hash como MD5 para os arquivos e compará-los. É possível que haja uma colisão de hash, mas não é muito provável.

Eu imagino que a comparação de bytes por byte seria mais rápida do que calcular o hash nos dois arquivos no momento em que você está fazendo a comparação. No entanto, se seu aplicativo pré-calcular o hash e armazenar metadados sobre seus arquivos, a comparação de hashes será significativamente mais rápida.

Provavelmente, o CRC não é o caminho a seguir, pois é apenas um mecanismo de detecção de erros, não um hash. (ou um hash ruim com muitas possíveis colisões)

Dave Rager
fonte
+1 Concordo. É muito mais provável que seu disco rígido seja quebrado em comparação com a colisão acidental de uma boa função de hash (o CRC32 é fraco - também concorda).
Michał Šrajer 19/01/12
2

Para ter 100% de certeza de que dois arquivos são idênticos, você realmente precisa verificar os bytes.

Por quê? Colisões hash, é por isso! Dependendo do algoritmo usado para o hash, a colisão pode ser mais ou menos provável, mas é possível. Seguindo estas etapas:

  1. Verificar tamanhos de arquivo
  2. Verificar tipos de mímica
  3. Verificar hash
  4. Verifique alguns deslocamentos aleatórios e compare os bits

Dará a você uma garantia muito alta de certeza de que os dois arquivos são os mesmos, no entanto, há uma chance muito (extremamente) pequena de você ter uma colisão em suas mãos. A escolha de quão longe você deseja ir com suas comparações será ditada pela situação.


fonte
Acho que se você escolher um bom algoritmo de hash, o 2. e o 4. não fornecerão a você um aumento real de qualidade "igual". Provavelmente 1. é necessário apenas para hash fraco também.
Michał Šrajer 19/01/12
1
-1 Isso não faz sentido. Se você escolher um bom algoritmo de hash, todas as outras etapas serão supérfluas. 1. e 4. já estão cobertos pelo que um hash faz e 2. não fazem sentido (a maioria dos sistemas de arquivos nem sequer tem uma noção de "tipo MIME" e, mesmo que tivessem, acrescenta muito pouca informação).
sleske
@sleske Estou dizendo que, em vez de fazer o hash do arquivo, que é uma operação intensiva, você pode executar algumas operações preliminares que não são tão pesadas.
Reconheço apenas 1 e 3 fazem muito sentido. (1) sinalizará a maioria dos casos de arquivos diferentes, economizando a necessidade de calcular o hash. O conflito de hash no mesmo arquivo de tamanho é tão improvável que não vale a pena se preocupar.
Michael Shaw
1

Como outros já disseram, é mais rápido fazer uma comparação byte a byte se os dois arquivos estiverem no mesmo sistema. Se você estiver tentando comparar vários arquivos, chegará ao ponto em que o hash é a melhor resposta se os arquivos estiverem no armazenamento giratório.

O hash realmente brilha quando você não tem todos os dados disponíveis. Por exemplo, os arquivos estão em máquinas diferentes. Também permite salvar os resultados dos cálculos e consultá-los mais tarde. (Este relatório é o mesmo que o antigo? Quando você faz o relatório salvar um hash. Quando você faz o próximo, você pode simplesmente comparar os hashes. Além de não precisar ler o antigo, não nem precisa ter uma cópia disponível.)

Loren Pechtel
fonte
0

Eu acho que você deve usar o utilitário de comparação de arquivos fornecido com o sistema operacional ou uma ferramenta de comparação de arquivos (consulte: ferramentas de comparação de arquivos wiki ) para comparar o conteúdo DEPOIS de verificar as propriedades do arquivo descritas por @ Nelson Nelson.

Não acho que a CRC seja 100% precisa e acho que sua precisão diminui com o tamanho do arquivo. Além disso, não sugiro que você escreva do zero, pois pode exigir muitos testes.

NoChance
fonte
0

É necessário ler todos os bytes para verificar se um arquivo copiado é idêntico ao original? SIM para ter 100% de certeza

É necessário ler todos os bytes para verificar se um arquivo copiado NÃO é idêntico ao original? NÃO

Portanto, para determinar rapidamente a não-identidade, verifique primeiro metadados como tamanho do arquivo e qualquer tipo de soma de verificação / CRC ou MIME que o sistema operacional / sistema de arquivos / armazenamento possa estar mantendo . Como eles são pré-calculados por esse sistema, você não paga esse custo no momento da comparação.

Se esse teste for aprovado, você ainda precisará comparar todos os bytes individualmente, se precisar de 100% de certeza, mas observe que em CPUs modernas com pipeline e usando vários threads e possivelmente vários processadores / CPUs, a comparação de blocos de arquivos grandes é MUITO rápida. e eficiente porque o processo é altamente paralelelizável. Muito mais rápido do que QUALQUER tipo de computação matemática envolvendo cada byte (embora alguns algoritmos também sejam paralelamente possíveis, mas talvez não tão facilmente ou tão bem). Isso porque as CPUs com pipeline podem realizar operações de comparação de blocos de memória em microcódigo ou mesmo hardware (muito rápido) e subsistemas de disco para memória são altamente otimizados para trazer grandes blocos de arquivos para / da memória, todos feitos em paralelo e com hardware. Se seu aplicativo faz esse tipo de coisa regularmente, e é um gargalo de desempenho conhecido, você deve implementá-lo em código multithread bem escrito que aproveita os recursos de paralelização de seu sistema operacional e hardware (talvez use uma linguagem projetada para esta).

Somente se você desejar processar cada arquivo uma vez e fazer várias comparações posteriormente (em que você lembra ["armazenar em cache"] o resultado da análise resumida ou "compactada" [como diz JohnFX]]), haverá um benefício significativo em fazê-lo, e mesmo assim, apenas para provar a diferença (provável); para provar a identidade, você ainda precisará fazer a comparação byte a byte.

user14517
fonte