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 recriarabc2
no servidor distante servidor deabc
epatch
apenas. -
Localmente, em vez de desperdiçar 8 GB para fazer backup de
abc
eabc2
, 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-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, masrsync --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 patchdiff-abc
com--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.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, useabc
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, poisrsync --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
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
eabc2
. Então, tenteidiff -ua abc abc2 > patch
, copieiabc
paraabc3
e tentei recuperarabc2
graças aabc3
epatch
:patch abc3 < patch
, mas não funcionou: no finalabc3
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) restaurarabc2
, fornecido apenasabc
epatch
? - 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.
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).mydiff abc abc2 > patchfile
emypatch 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-first128mb
com , nenhuma correspondência será encontrada, então pode não ser eficiente?