Difundir archivos binarios en Python

Tengo dos archivos binarios. Se ven algo así, pero los datos son más aleatorios:

Presentar un:

FF FF FF FF 00 00 00 00 FF FF 44 43 42 41 FF FF ... 

Archivo B:

 41 42 43 44 00 00 00 00 44 43 42 41 40 39 38 37 ... 

Lo que me gustaría es llamar algo como:

 >>> someDiffLib.diff(file_a_data, file_b_data) 

Y recibe algo como:

 [Match(pos=4, length=4)] 

Indica que en ambos archivos los bytes en la posición 4 son los mismos para 4 bytes. La secuencia 44 43 42 41 no coincidiría porque no están en las mismas posiciones en cada archivo.

¿Hay alguna biblioteca que me ayude? ¿O debería simplemente escribir los bucles para hacer la comparación?

Puedes usar itertools.groupby() para esto, aquí hay un ejemplo:

 from itertools import groupby # this just sets up some byte strings to use, Python 2.x version is below # instead of this you would use f1 = open('some_file', 'rb').read() f1 = bytes(int(b, 16) for b in 'FF FF FF FF 00 00 00 00 FF FF 44 43 42 41 FF FF'.split()) f2 = bytes(int(b, 16) for b in '41 42 43 44 00 00 00 00 44 43 42 41 40 39 38 37'.split()) matches = [] for k, g in groupby(range(min(len(f1), len(f2))), key=lambda i: f1[i] == f2[i]): if k: pos = next(g) length = len(list(g)) + 1 matches.append((pos, length)) 

O lo mismo que arriba usando una lista de comprensión:

 matches = [(next(g), len(list(g))+1) for k, g in groupby(range(min(len(f1), len(f2))), key=lambda i: f1[i] == f2[i]) if k] 

Aquí está la configuración del ejemplo si está utilizando Python 2.x:

 f1 = ''.join(chr(int(b, 16)) for b in 'FF FF FF FF 00 00 00 00 FF FF 44 43 42 41 FF FF'.split()) f2 = ''.join(chr(int(b, 16)) for b in '41 42 43 44 00 00 00 00 44 43 42 41 40 39 38 37'.split()) 

La solución proporcionada por itertools.groupby funciona bien, pero es bastante lenta.

Escribí un bash bastante ingenuo usando numpy y lo probé frente a la otra solución en un archivo particular de 16MB que tenía, y fue aproximadamente 42 veces más rápido en mi máquina. Alguien familiarizado con numpy probablemente podría mejorar esto significativamente.

 import numpy as np def compare(path1, path2): x,y = np.fromfile(path1, np.int8), np.fromfile(path2, np.int8) length = min(x.size, y.size) x,y = x[:length], y[:length] z = np.where(x == y)[0] if(z.size == 0) : return z borders = np.append(np.insert(np.where(np.diff(z) != 1)[0] + 1, 0, 0), len(z)) lengths = borders[1:] - borders[:-1] starts = z[borders[:-1]] return np.array([starts, lengths]).T