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 archivoabc2completo (¡volvería a tardar unas horas!), y vuelva a crearabc2en el servidor deabcypatchúnicamente. -
Localmente, en lugar de desperdiciar 8 GB para hacer copias de seguridad de
abcyabc2, 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:
-
bsdiffusa 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 . -
bspatchusa 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 oldfileasí 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 > patchfileymypatch 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-first128mbconabc2-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í .
-
-usalida NUM (por defecto 3) líneas de contexto unificado -
-atratar 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
abcyabc2muy similares de 256 MB. Luego probédiff -ua abc abc2 > patch, luego copiéabcaabc3e intenté recuperarabc2gracias aabc3ypatch:patch abc3 < patch, pero no funcionó: al finalabc3era 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 -lque 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
patchy 2) restaurarabc2, dado soloabcypatch? - 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
patchque 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-batchrsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], perorsync --read-batch=abc-diff abcfuncionó con éxito.¿Cuál es la diferencia entre estos dos comandos similares?abccomo entrada, aplicar el parchediff-abccon--read-batchpero 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.exedisponible)$1tuviera 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, utiliceabcen lugar de «. Yo ‘ asumo que$1tení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 abcfunciona 🙂