Diferença de dois grandes arquivos binários brutos semelhantes

Digamos que eu tenha um arquivo de 4 GB abc no meu computador local. Fiz upload para um servidor distante via SFTP, demorou algumas horas.

Agora modifiquei um pouco o arquivo (provavelmente no máximo 50 MB, mas não bytes consecutivos neste arquivo) localmente, e o salvei em abc2. Também mantive o arquivo original abc no meu computador local.

Como calcular uma diferença binária de abc e abc2?

Aplicativos:

  • Eu só pude enviar um arquivo patch (provavelmente no máximo 100 MB) para o servidor distante, em vez de recarregar todo o arquivo abc2 (levaria algumas horas novamente!) e recriar abc2 no servidor distante servidor de abc e patch apenas.

  • Localmente, em vez de desperdiçar 8 GB para fazer backup de abc e abc2, só pude salvar abc + patch, então levaria < somente 4100 MB.

Como fazer isso?

PS: para texto, eu sei diff, mas aqui estou procurando algo que poderia funcionar para qualquer formato binário bruto, poderia ser arquivos zip ou executáveis ou mesmo outros tipos de arquivo.

PS2: Se possível, não quero usar rsync; Eu sei que ele pode replicar as alterações entre 2 computadores de maneira eficiente (não reenviando os dados que não foram alterados), mas aqui eu realmente quero ter um arquivo patch, que seja reproduzível posteriormente se Eu tenho abc e patch.

Resposta

Para o segundo aplicativo / problema, eu usaria um programa de backup de desduplicação como restic ou borgbackup, em vez de tentar para controlar manualmente os “patches” ou diferenças. O programa de backup restic permite que você faça backup de diretórios de várias máquinas para o mesmo repositório de backup, desduplicando os dados de backup entre fragmentos de arquivos de uma máquina individual e também entre as máquinas. (Não tenho experiência de usuário com borgbackup, então não posso dizer nada sobre esse programa.)

Calculando e armazenando uma diferença de abc e abc2 podem ser feitos com rsync.

Este é um exemplo com abc e abc2 sendo 153 MB. O arquivo abc2 foi modificado substituindo o primeiros 2,3 MB do arquivo com alguns outros dados:

 $ ls -lh total 626208 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2  

Nós criamos fora patch para transformar abc em abc2 e chamá-lo de abc-diff:

 $ rsync --only-write-batch=abc-diff abc2 abc  
 $ ls -lh total 631026 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw------- 1 kk wheel 2.3M Feb 3 17:03 abc-diff -rwx------ 1 kk wheel 38B Feb 3 17:03 abc-diff.sh -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2  

O arquivo gerado abc-diff é o diff real (seu “arquivo de patch”), enquanto abc-diff.sh éum script de shell curto que rsync cria para você:

 $ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}  

Este script modifica abc para que se torne idêntico a abc2, dado o arquivo abc-diff:

 $ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2  

O arquivo abc-diff agora pode ser transferido para qualquer outro lugar que você tenha abc. Com o comando rsync --read-batch=abc-diff abc, você aplicaria o patch ao arquivo abc, transformando seu conteúdo para ser o mesmo de abc2 arquivo no sistema onde você criou o diff.

Reaplicar o patch uma segunda vez parece seguro. Não há mensagens de erro nem o conteúdo do arquivo muda (a soma de verificação MD5 não muda).

Observe que, a menos que você crie um “patch reverso” explícito, não há maneira de desfazer o aplicativo facilmente do patch.


Eu também testei escrever a modificação de 2,3 MB em algum outro lugar nos dados abc2, um pouco mais adiante (em cerca de 50 MB), bem como no início. O “patch” gerado tinha 4,6 MB de tamanho, sugerindo que apenas os bits modificados foram armazenados no patch.

Comentários

  • Muito obrigado @Kusalananda, ‘ é ótimo! PS: rsync --read-batch=abc-diff ${1:-abc} (script .sh gerado automaticamente) deu remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], mas rsync --read-batch=abc-diff abc funcionou com sucesso.Qual é a diferença entre esses dois comandos semelhantes?
  • 2/2 Existe uma maneira de tomar abc como entrada, aplicar o patch diff-abc com --read-batch, mas não modifique abc ” no local “, mas em vez disso, a saída para um novo arquivo abc3? (se possível, tudo com rsync, sem tubulação, para que funcione facilmente no Linux, bem como no Windows, que também tem rsync.exe disponível)
  • @Basj Os comandos fariam coisas diferentes se $1 tivesse um valor. ${1:-abc} significa ” usar o primeiro parâmetro posicional ($1) a menos que ‘ s vazio ou indefinido. No caso de ‘ estar vazio ou indefinido, use abc em vez de “. Eu ‘ estou supondo que $1 tinha um valor quando você tentou, possivelmente algo que interpretou como um endereço de destino remoto.
  • @Basj I ‘ Não tenho certeza de que isso seja possível, mas ‘ ll dê uma olhada amanhã depois de dormir.
  • Obrigado por sua resposta sobre ${1:-abc}. Provavelmente falhou porque tentei no Windows (eu ‘ estou usando rsync no Linux para meu servidor distante e no Windows localmente). Mas ‘ é perfeito, pois rsync --read-batch=abc-diff abc funciona 🙂

Resposta

Como calcular um diff binário de abc e abc2?

Usando bsdiff / bspatch ou xdelta e outros.

$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created 

No entanto, essas advertências das páginas de manual devem ser observadas:

  • bsdiff usa memória igual a 17 vezes o tamanho de oldfile e requer um tamanho de conjunto de trabalho mínimo absoluto de 8 vezes o tamanho do oldfile .
  • bspatch usa memória igual ao tamanho de oldfile mais o tamanho de newfile , mas pode tolerar um conjunto de trabalho muito pequeno sem uma perda dramática de desempenho.

Comentários

  • Você poderia mostrar um exemplo?
  • Obrigado por sua resposta. bsdiff uses memory equal to 17 times the size of oldfile então isso não ‘ funcionará normalmente para arquivos de 4 GB (pelo menos em minha máquina de 8 GB de RAM).
  • @Basj O que é possível é dividir o arquivo de 4 GB em arquivos menores (digamos 128 MB cada) e fazer deltas individuais. Isso pode ser agrupado em um script. chopped-bsdiff: corte os arquivos, faça bsdiffs em pares, coloque-os em um arquivo. chopped-bspatch: ler patches em pares do arquivo, aplicar a pedaços do arquivo de entrada, catenar a saída.
  • @Kaz entendo, mas ‘ estou procurando mais uma ferramenta pronta para usar que pode ser chamada em 1 linha (mydiff abc abc2 > patchfile e mypatch abc patchfile > abc3), independentemente do tamanho. Além disso, se eu dividir em blocos de 128 MB, o que acontecerá se o primeiro 1 GB de abc == o último (último) 1 GB de abc2 ? Quando ‘ compararemos abc-first128mb com , nenhuma correspondência será encontrada, então pode não ser eficiente?

Resposta

Você tentou apenas forçar diff para tratar os arquivos como texto:

diff -ua abc abc2 

Conforme explicado aqui .

  • -u linhas de saída NUM (padrão 3) de contexto unificado
  • -a tratar todos os arquivos como texto

Isso deve lhe dar um patch. A desvantagem disso é que as “linhas” podem ser muito longas e podem inchar o patch.

Comentários

  • Ops, sim, você não ‘ t realmente deseja o n. Eu ‘ estou interessado em saber se funciona porque ‘ não tenho certeza de quanto tempo o ” linhas ” serão.
  • Obrigado pelo seu comentário! Criei dois arquivos de 256 MB muito semelhantes abc e abc2. Então, tentei diff -ua abc abc2 > patch, copiei abc para abc3 e tentei recuperar abc2 graças a abc3 e patch: patch abc3 < patch, mas não funcionou: no final abc3 tinha apenas 1 KB em vez de 256 MB. Alguma ideia?
  • Hmmm, não tenho certeza do que aconteceu. Acabei de fazer isso na minha máquina e funcionou melhor do que eu esperava.Peguei um arquivo de 382 milhões que eram números inteiros aleatórios gravados em binário em um arquivo. Eu mudei 3 bytes nele e fiz o diff e o patch e funcionou. Os arquivos resultantes eram md5sum iguais.
  • Se um arquivo grande não tivesse byte 0x0a, ou seja, nova linha ou muito poucos, suspeito que não ‘ t funcionam tão bem, seria interessante testar.
  • Oh, com certeza. Você pode adivinhar com base em um binário com wc -l, que procurará quebras de linha e, na minha experiência, é executado muito rapidamente. Eu esperaria que em um binário arbitrário funcionasse muito bem. Por exemplo, em minha máquina eu encontrei um 252M mp4 que tinha 1,2 milhões ” linhas ” e um 59M .deb que tinha cerca de 230k, então a média ” linhas ” de menos de 220 bytes e 258 bytes, respectivamente. Eu não ‘ não vejo por que esses arquivos seriam tão diferentes de outros, mas você definitivamente pode ter azar. Na prática, suspeito que funcionaria muito bem; caso contrário, ‘ ainda é um hack divertido.

Resposta

Use xdelta , foi criado exatamente para este tipo de uso. Baseado em VCDIFF (RFC 3284) nas versões mais recentes.

Comentários

  • O link não está funcionando (há outro URL?). Você também pode adicionar um exemplo em algumas linhas para mostrar como: 1) calcular o arquivo diff patch e 2) restaurar abc2 , fornecido apenas abc e patch?
  • Desculpe, URL fixo
  • Obrigado @vonbrand . Você teria um exemplo assim?

Resposta

Complementa para outras respostas de acordo com meus testes:

Com diff

criei dois arquivos de 256 MB muito semelhantes abc e abc2. Então, vamos criar o arquivo diff:

diff -ua abc abc2 > abc-abc2.diff 

Agora vamos tentar recuperar abc2 graças ao arquivo abc original e abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

ou

cp abc abc3 patch abc3 -i abc-abc2.diff 

ou

patch abc -i abc-abc2.diff -o abc3 

Funciona no Linux. Eu também tentei no Windows (patch.exe e diff.exe também estão disponíveis), mas por um motivo desconhecido ele falhou: o arquivo abc3 produzido tem apenas 1 KB em vez de 256 MB (I ” atualizarei esta resposta mais tarde aqui).

Com rsync

Conforme detalhado na resposta aceita, isso funciona:

rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3 

Com rdiff

Conforme detalhado em este resposta , esta também é uma solução:

rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3 

Testado também no Windows com rdiff.exe de aqui e funciona.

Comentários

  • Eu ‘ estou supondo que patch falhou no Windows porque estava lendo o arquivo de entrada no modo ” text ” que sinaliza o fim do arquivo quando encontra um CONTROLE -Z (byte 0x18) no arquivo de entrada. Este é um modo legado dos primeiros dias do DOS, quando o diretório não registrava a duração de o arquivo e, portanto, o comprimento do arquivo foi calculado com base no número de setores de 512 bytes. Se você puder dizer a patch para abrir o arquivo no modo binário, ele não deve ‘ ter este erro.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *