3 votos

Fusionar bytes distintos de cero en archivos grandes

Estoy tratando de rescate en un viejo rayado DVD que rasga a ISO. Tengo dos lectores y creado una ISO de cada uno. Cada lector es incapaz de leer ciertos diferentes bytes de los DVD y los reemplaza con los 0s. Al comparar los archivos con cmp -l file1.iso file2.iso, veo que ciertas bytes de la izquierda es 0 mientras que algunos otros bytes de la derecha son 0 (el correspondiente bytes en los otros archivos son no-cero). Quiero crear un 3er archivo, decir file3.iso que se fusiona con la no-cero diferentes bytes de los dos anteriores de los archivos. Como un ejemplo, supongamos por simplicidad que cada archivo tiene 6 bytes de la siguiente manera

file1.iso   file2.iso
---------   ---------
0           0
1           1
2           0
3           0
0           4
0           5

file3.iso debe ser como sigue:

0
1
2
3
4
5

Los archivos son bastante grandes (alrededor de 8 GB). Cada archivo tiene el mismo número de bytes. Estoy usando Ubuntu 16.04

Puede alguien sugerir la forma más sencilla de hacer lo que quiero. Puedo usar la salida de cmp -l como datos intermedios, pero quieren evitar tener que escribir código.

2voto

Burnaby Puntos 57

Escribí un script en Python para ti.

 #!/usr/bin/env python3
'''
Given two input files and one output file, merge the input files on
matching bytes or bytes that are null in one file but not the other.
Non-matching non-null bytes will raise a ValueError.
'''

import sys

args = sys.argv[1:]

file1 = open(args[0], 'rb')
file2 = open(args[1], 'rb')
file_out = open(args[2], 'wb')

def get_bytes(file):
    '''Return a generator that yields each byte in the given file.'''
    def get_byte():
        return file.read(1)
    return iter(get_byte, b'')

for i, (byte1, byte2) in enumerate(zip(get_bytes(file1), get_bytes(file2))):
    if byte1 == byte2:
        byte_out = byte1
    elif ord(byte1) == 0:
        byte_out = byte2
    elif ord(byte2) == 0:
        byte_out = byte1
    else:
        msg = 'Bytes at {:#x} are both non-zero and do not match: {}, {}'
        raise ValueError(msg.format(i, byte1, byte2))
    file_out.write(byte_out)
 

Hazlo ejecutable y luego llámalo así:

 $ ./test.py file1.iso file2.iso file3.iso
 

O para abreviar:

 $ ./test.py file{1,2,3}.iso
 

Ps. Recientemente he estado estudiando la lectura de archivos de diferentes maneras, así que es una buena casualidad.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: