Como comparar partes de arquivos por hash?

19

Eu tenho um arquivo baixado com sucesso e outro com falha no download (apenas os primeiros 100 MB de um arquivo grande) que suspeito ser o mesmo arquivo.

Para verificar isso, gostaria de verificar seus hashes, mas como tenho apenas uma parte do arquivo baixado sem êxito, quero apenas fazer o hash dos primeiros megabytes.

Como eu faço isso?

O sistema operacional seria o Windows, mas eu tenho o Cygwin e o MinGW instalados.

pecou
fonte
1
A comparação eficiente de um arquivo em um computador local com outro arquivo em um computador distante é uma parte essencial do rsync , que compara partes dos arquivos com uma função de hash especial.
David Cary
@DavidCary No meu caso, eu não tenho acesso shell para o computador remoto, mas obrigado pela dica, vou ler a página de manual
pecou

Respostas:

56

Criar hashes para comparar arquivos faz sentido se você comparar um arquivo com muitos ou quando comparar muitos arquivos entre si.

Não faz sentido ao comparar dois arquivos apenas uma vez: O esforço para calcular os hashes é pelo menos tão alto quanto caminhar sobre os arquivos e compará-los diretamente.

Uma ferramenta eficiente de comparação de arquivos é cmp:

cmp --bytes $((100 * 1024 * 1024)) file1 file2 && echo "File fragments are identical"

Você também pode combiná-lo com ddpara comparar partes arbitrárias (não necessariamente desde o início) de dois arquivos, por exemplo:

cmp \
    <(dd if=file1 bs=100M count=1 skip=1 2>/dev/null) \
    <(dd if=file2 bs=100M count=1 skip=1 2>/dev/null) \
&& echo "File fragments are identical"
Konrad Rudolph
fonte
6
Nota: criar hashes para comparar arquivos também faz sentido se você deseja evitar a leitura de dois arquivos ao mesmo tempo.
Kamil Maciorowski
1
@KamilMaciorowski Sim, é verdade. Mas esse método ainda será geralmente mais rápido do que comparar hashes no caso em pares.
Konrad Rudolph
8
Esta é a solução para viagem. cmpé certo que 99,99% já estará instalado se você estiver bashexecutando, e ele faz o trabalho. De fato, cmp -n 131072 one.zip two.zip também fará o trabalho. Menos caracteres para digitar e execução mais rápida. Calcular um hash não faz sentido. Ele exige a leitura de todo o arquivo de 100 MB, além de uma parte de 100 MB do arquivo completo, o que é inútil. Se forem arquivos zip e forem diferentes, haverá uma diferença nas primeiras centenas de bytes. No entanto, o Readahead fornece 128k por padrão, para que você possa comparar 128k (o mesmo custo que comparar 1 byte).
Damon
19
A --bytesopção está apenas complicando a tarefa. Basta executar cmpsem essa opção e ele mostrará o primeiro byte que difere entre os arquivos. Se todos os bytes forem iguais, será exibido EOFno arquivo mais curto. Isso fornecerá mais informações do que o seu exemplo - quantos bytes estão corretos.
Pabouk
2
Se você possui o GNU cmp(e, acho que praticamente todo mundo), você pode usar argumentos --ignore-initiale --bytesnão complicar as coisas com invocações de dd.
Christopher Schultz
12

Me desculpe, eu não posso exatamente tentar isso, mas desta forma vai funcionar

dd if=yourfile.zip of=first100mb1.dat bs=100M count=1
dd if=yourotherfile.zip of=first100mb2.dat bs=100M count=1

Isso lhe dará os primeiros 100 megabytes de ambos os arquivos.

Agora pegue os hashes:

sha256sum first100mb1.dat && sha256sum first100mb2.dat 

Você também pode executá-lo diretamente:

dd if=yourfile.zip bs=100M count=1 | sha256sum 
dd if=yourotherfile.zip bs=100M count=1 | sha256sum 
davidbaumann
fonte
1
Existe uma maneira de canalizar dd de alguma forma no sha256sum sem o arquivo intermediário?
pecou
1
Eu adicionei outra maneira de acordo com o seu pedido
davidbaumann
8
Por que criar os hashes? Isso é muito menos eficiente do que apenas comparar os fragmentos de arquivo diretamente (usando cmp).
Konrad Rudolph
No exemplo de código do meio, você diz first100mb1.dat duas vezes. Você quis dizer first100mb 2 .dat para o segundo?
Doppelgreener 06/12/19
@KonradRudolph, "Por que criar os hashes?" Sua solução (usando cmp) é um vencedor sem dúvida. Mas essa maneira de resolver o problema (usando hashes) também tem o direito de existir enquanto ele realmente resolver o problema (:
VL-80
7

Todo mundo parece seguir a rota Unix / Linux com isso, mas apenas comparar dois arquivos pode ser feito facilmente com os comandos padrão do Windows:
FC /B file file2

O FC está presente em todas as versões do Windows NT já criadas. E (se bem me lembro) também estava presente no DOS.
É um pouco lento, mas isso não importa para o uso único.

Tonny
fonte
6

Você pode apenas comparar diretamente os arquivos, com um programa binário / hex diff vbindiff. Ele compara rapidamente arquivos de até 4 GB no Linux e Windows.

Parece algo assim, apenas com a diferença destacada em vermelho (1B vs 1C):

one                                       
0000 0000: 30 5C 72 A7 1B 6D FB FC  08 00 00 00 00 00 00 00  0\r..m.. ........  
0000 0010: 00 00 00 00                                       ....
0000 0020:
0000 0030:
0000 0040:
0000 0050:
0000 0060:
0000 0070:
0000 0080: 
0000 0090: 
0000 00A0: 

two        
0000 0000: 30 5C 72 A7 1C 6D FB FC  08 00 00 00 00 00 00 00  0\r..m.. ........  
0000 0010: 00 00 00 00                                       ....               
0000 0020: 
0000 0030:
0000 0040:
0000 0050:
0000 0060:
0000 0070:
0000 0080:
0000 0090:                                
0000 00A0:             
┌──────────────────────────────────────────────────────────────────────────────┐
Arrow keys move  F find      RET next difference  ESC quit  T move top        
C ASCII/EBCDIC   E edit file   G goto position      Q quit  B move bottom     
└──────────────────────────────────────────────────────────────────────────────┘ 
Xen2050
fonte
No meu caso, os arquivos são arquivos zip, portanto, não há texto significativo lá. A comparação do valor do hash deve ser mais rápida e menos propensa a erros.
pecou
2
Se você quer dizer texto ASCII, isso é irrelevante. vbindiff(e Konrad cmp) compara dados binários, byte por byte. Na verdade tem valores são muito mais propensos a colisões experiência
Xen2050
* Significado "De fato, os valores de HASH são muito mais propensos a colisões" no comentário acima, perdi o h!
Xen2050
0

Eu sei que diz para Bash, mas OP também afirma que eles têm Windows. Para quem quer / requer uma solução do Windows, existe um programa chamado HxD, que é um editor hexadecimal que pode comparar dois arquivos. Se os arquivos tiverem tamanhos diferentes, será informado se as peças disponíveis são as mesmas. E, se necessário, é capaz de executar somas de verificação para o que estiver selecionado no momento. É gratuito e pode ser baixado no site HxD . Não tenho nenhuma conexão com o (s) autor (es), apenas uso-o há anos.

Blerg
fonte
0

O cmp informará quando dois arquivos são idênticos até o tamanho do arquivo menor:

$ dd if=/dev/random bs=8192 count=8192 > a
8192+0 records in
8192+0 records out
67108864 bytes transferred in 0.514571 secs (130417197 bytes/sec)
$ cp a b
$ dd if=/dev/random bs=8192 count=8192 >> b 
8192+0 records in
8192+0 records out
67108864 bytes transferred in 0.512228 secs (131013601 bytes/sec)
$ cmp a b
cmp: EOF on a

O cmp está dizendo que a comparação encontrou um EOF no arquivo a antes de detectar qualquer diferença entre os dois arquivos.

Jim L.
fonte
Bom ponto. Se você ainda não viu, foi o que pabouk já comentou sobre a resposta aceita.
pecou