Digamos que tengo un archivo de 4 GB abc
en mi computadora local. Lo he subido a un servidor distante a través de SFTP, tomó algunas horas.
Ahora he modificado ligeramente el archivo (probablemente 50 MB como máximo, pero no bytes consecutivos en este archivo) localmente, y lo guardé en abc2
. También guardé el archivo original abc
en mi computadora local.
¿Cómo calcular una diferencia binaria de abc
y abc2
?
Aplicaciones:
-
Solo pude enviar un archivo
patch
(probablemente un máximo de 100 MB) a el servidor distante, en lugar de volver a cargar el archivoabc2
completo (¡volvería a tardar unas horas!), y vuelva a crearabc2
en el servidor deabc
ypatch
únicamente. -
Localmente, en lugar de desperdiciar 8 GB para hacer copias de seguridad de
abc
yabc2
, solo pude ahorrarabc
+patch
, por lo que se necesitarían < 4100 MB solamente.
¿Cómo hacer esto?
PD: para texto, sé diff
, pero aquí estoy buscando algo que podría funcionar para cualquier formato binario sin procesar, podrían ser archivos zip o ejecutables o incluso otros tipos de archivos.
PS2: Si es posible, no quiero usar rsync
; Sé que puede replicar cambios entre 2 computadoras de una manera eficiente (sin reenviar datos que no han cambiado), pero aquí realmente quiero tener un archivo patch
, que se pueda reproducir más adelante si Tengo abc
y patch
.
Respuesta
Para la segunda aplicación / problema, usaría un programa de respaldo de deduplicación como restic
o borgbackup
, en lugar de intentar para realizar un seguimiento manual de los «parches» o diferencias. El programa de respaldo restic
le permite respaldar directorios de varias máquinas en el mismo repositorio de respaldo, deduplicando los datos de respaldo tanto entre fragmentos de archivos de una máquina individual como entre máquinas. (No tengo experiencia de usuario con borgbackup
, así que no puedo decir nada sobre ese programa).
Calculando y almacenando una diferencia de abc
y abc2
se pueden hacer con rsync
.
Este es un ejemplo con abc
y abc2
siendo 153 MB. El archivo abc2
se modificó sobrescribiendo el primeros 2,3 MB del archivo con algunos otros datos:
$ 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
Creamos parche para transformar abc
en abc2
y llamarlo 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
El archivo generado abc-diff
es el diff real (su «archivo de parche»), mientras que abc-diff.sh
esun breve script de shell que rsync
crea para usted:
$ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}
Este script modifica abc
para que sea idéntico a abc2
, dado el archivo abc-diff
:
$ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2
El archivo abc-diff
ahora se puede transferir a cualquier otro lugar que tenga abc
. Con el comando rsync --read-batch=abc-diff abc
, aplicaría el parche al archivo abc
, transformando su contenido para que sea el mismo que el abc2
archivo en el sistema donde creó la diferencia.
Volver a aplicar el parche por segunda vez parece seguro. No hay mensajes de error ni cambia el contenido del archivo (la suma de comprobación MD5 no cambia).
Tenga en cuenta que, a menos que cree un «parche inverso» explícito, no hay forma de deshacer fácilmente la aplicación del parche.
También probé escribir la modificación de 2,3 MB en algún otro lugar de los datos abc2
, un poco más adelante (a unos 50 MB), así como al principio. El «parche» generado tenía un tamaño de 4,6 MB, lo que sugiere que solo los bits modificados se almacenaron en el parche.
Comentarios
Respuesta
¿Cómo calcular una diferencia binaria de abc y abc2?
Usando bsdiff / bspatch o xdelta y otros.
$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created
Sin embargo, se deben tener en cuenta estas advertencias de las páginas de manual:
-
bsdiff
usa una memoria equivalente a 17 veces el tamaño de archivo antiguo , y requiere un tamaño de conjunto de trabajo mínimo absoluto de 8 veces el tamaño de archivo antiguo . -
bspatch
usa una memoria igual al tamaño de archivo antiguo más el tamaño de archivo nuevo , pero puede tolerar un conjunto de trabajo muy pequeño sin una pérdida dramática de rendimiento.
Comentarios
- ¿Podría mostrar un ejemplo?
- Gracias por su respuesta.
bsdiff uses memory equal to 17 times the size of oldfile
así que esto no ‘ normalmente funciona para archivos de 4GB (al menos en mi máquina de 8GB RAM). - @Basj Lo que es posible es dividir el archivo de 4 GB en archivos más pequeños (digamos 128 MB cada uno) y hacer deltas individuales. Esto podría incluirse en un guión. chopped-bsdiff: corta los archivos, haz bsdiffs por pares, ponlos en un archivo. chopped-bspatch: leer parches por pares del archivo, aplicar a fragmentos del archivo de entrada, clasificar la salida.
- @Kaz Ya veo, pero ‘ m más buscando una herramienta lista para usar que se puede llamar en 1 línea (
mydiff abc abc2 > patchfile
ymypatch abc patchfile > abc3
) independientemente del tamaño. Además, si corto en trozos de 128 MB, ¿qué sucede si el primer 1 GB deabc
== el último (final) 1 GB deabc2
? Cuando ‘ comparemosabc-first128mb
conabc2-first128mb
, no se encontrará ninguna coincidencia, por lo que podría no ser eficiente?
Responder
¿Ha intentado forzar diff
para tratar los archivos como texto:
diff -ua abc abc2
Como se explica aquí .
-
-u
salida NUM (por defecto 3) líneas de contexto unificado -
-a
tratar todos los archivos como texto
Esto debería proporcionarle un parche. La desventaja de esto es que las «líneas» pueden ser bastante largas y eso podría inflar el parche.
Comentarios
- Vaya, sí, no ‘ t realmente quiero el
n
. Estoy ‘ interesado en saber si funciona porque ‘ no estoy seguro de cuánto tiempo » lines » será. - ¡Gracias por tu comentario! Creé dos archivos
abc
yabc2
muy similares de 256 MB. Luego probédiff -ua abc abc2 > patch
, luego copiéabc
aabc3
e intenté recuperarabc2
gracias aabc3
ypatch
:patch abc3 < patch
, pero no funcionó: al finalabc3
era solo 1 KB en lugar de 256 MB. ¿Alguna idea? - Hmmm, no estoy seguro de lo que pasó. Simplemente lo hice en mi máquina y funcionó mejor de lo que esperaba.Tomé un archivo de 382M que contenía enteros aleatorios escritos en binario en un archivo. Cambié 3 bytes en él e hice la diferencia y el parche y funcionó. Los archivos resultantes eran md5sum iguales.
- Si un archivo grande no tiene byte
0x0a
, es decir, nueva línea, o muy pocos, sospecho que no lo haría ‘ No funciona tan bien, sería interesante probarlo. - Oh, seguro. Puede hacer una suposición fundamentada sobre un binario con
wc -l
que buscará saltos de línea y, en mi experiencia, se ejecuta muy rápidamente. Esperaría que en un binario arbitrario funcione bastante bien. Por ejemplo, en mi máquina encontré un mp4 de 252M que tenía 1.2 millones de » líneas «, y un que tenía alrededor de 230k, por lo que las » líneas » promedio de menos de 220 bytes y 258 bytes respectivamente. No ‘ no veo por qué estos archivos serían tan diferentes a los demás, pero definitivamente podrías tener mala suerte. En la práctica, sospecho que funcionaría bastante bien y si no ‘ sigue siendo un truco divertido.
Responder
Use xdelta , fue creado exactamente para este tipo de usos. Basado en VCDIFF (RFC 3284) en las últimas versiones.
Comentarios
- El enlace no funciona (¿hay otra URL?). También podría agregar un ejemplo en unas pocas líneas para mostrar cómo: 1) calcular el archivo diff
patch
y 2) restaurarabc2
, dado soloabc
ypatch
? - Lo sentimos, URL fija
- Gracias @vonbrand . ¿Tendría un ejemplo así?
Respuesta
Complementos de otras respuestas de acuerdo con mis pruebas:
Con diff
Creé dos archivos abc
y . Luego, creemos el archivo diff:
diff -ua abc abc2 > abc-abc2.diff
Ahora intentemos recuperar abc2
gracias al archivo abc
original y abc-abc2.diff
:
cp abc abc3 patch abc3 < abc-abc2.diff
o
cp abc abc3 patch abc3 -i abc-abc2.diff
o
patch abc -i abc-abc2.diff -o abc3
Funciona en Linux. También probé en Windows (patch.exe y diff.exe también están disponibles), pero por una razón desconocida falló: el archivo abc3
producido es de solo 1 KB en lugar de 256 MB (I » Actualizaré esta respuesta más adelante aquí).
Con rsync
Como se detalla en la respuesta aceptada, esto funciona:
rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3
Con rdiff
Como se detalla en esto answer , esta también es una solución:
rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3
Probado también en Windows con rdiff.exe de aquí y funciona.
Comentarios
- Yo ‘ supongo que el parche falló en Windows porque estaba leyendo el archivo de entrada en el modo » text » que indica el final del archivo cuando encuentra un CONTROL -Z (byte 0x18) en el archivo de entrada. Este es un modo heredado de los primeros días de DOS cuando el directorio no registraba la longitud de el archivo y, por tanto, la longitud del archivo se calculó en función del número de sectores de 512 bytes. Si puede decirle a
patch
que abra el archivo en modo binario, no debería ‘ tener este error.
rsync --read-batch=abc-diff ${1:-abc}
(script .sh generado automáticamente) dioremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, perorsync --read-batch=abc-diff abc
funcionó con éxito.¿Cuál es la diferencia entre estos dos comandos similares?abc
como entrada, aplicar el parchediff-abc
con--read-batch
pero sin modificarabc
» in situ «, sino que se envía a un nuevo archivoabc3
? (si es posible, todo conrsync
, sin canalización, para que funcione fácilmente en Linux y Windows, que también tienersync.exe
disponible)$1
tuviera un valor.${1:-abc}
significa » usar el primer parámetro posicional ($1
) a menos que ‘ s vacío o indefinido. En el caso de que ‘ esté vacío o no esté definido, utiliceabc
en lugar de «. Yo ‘ asumo que$1
tenía un valor cuando lo probaste, posiblemente algo que interpretó como un dirección de destino remoto.${1:-abc}
. Probablemente falló porque lo probé en Windows (‘ estoy usando rsync tanto en Linux para mi servidor distante como en Windows localmente). Pero ‘ es perfecto ya quersync --read-batch=abc-diff abc
funciona 🙂