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 arquivoabc2(levaria algumas horas novamente!) e recriarabc2no servidor distante servidor deabcepatchapenas. -
Localmente, em vez de desperdiçar 8 GB para fazer backup de
abceabc2, só pude salvarabc+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) deuremote destination is not allowed with --read-batchrsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], masrsync --read-batch=abc-diff abcfuncionou com sucesso.Qual é a diferença entre esses dois comandos semelhantes? - 2/2 Existe uma maneira de tomar
abccomo entrada, aplicar o patchdiff-abccom--read-batch, mas não modifiqueabc” no local “, mas em vez disso, a saída para um novo arquivoabc3? (se possível, tudo comrsync, sem tubulação, para que funcione facilmente no Linux, bem como no Windows, que também temrsync.exedisponível) - @Basj Os comandos fariam coisas diferentes se
$1tivesse 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, useabcem vez de “. Eu ‘ estou supondo que$1tinha 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, poisrsync --read-batch=abc-diff abcfunciona 🙂
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:
-
bsdiffusa 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 . -
bspatchusa 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
Resposta
Você tentou apenas forçar diff para tratar os arquivos como texto:
diff -ua abc abc2
Conforme explicado aqui .
-
-ulinhas de saída NUM (padrão 3) de contexto unificado -
-atratar 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
abceabc2. Então, tenteidiff -ua abc abc2 > patch, copieiabcparaabc3e tentei recuperarabc2graças aabc3epatch:patch abc3 < patch, mas não funcionou: no finalabc3tinha 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.debque 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
patche 2) restaurarabc2, fornecido apenasabcepatch? - 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
patchpara abrir o arquivo no modo binário, ele não deve ‘ ter este erro.
bsdiff uses memory equal to 17 times the size of oldfileentão isso não ‘ funcionará normalmente para arquivos de 4 GB (pelo menos em minha máquina de 8 GB de RAM).mydiff abc abc2 > patchfileemypatch 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 deabc== o último (último) 1 GB deabc2? Quando ‘ compararemosabc-first128mbcom , nenhuma correspondência será encontrada, então pode não ser eficiente?