2016-08-17 3 views
0

J'ai un fichier avec des octets de codage little-endian, je veux prendre N octets, spécifier endianess et les convertir en nombre décimal en utilisant python (n'importe quelle version). Comment le faire correctement?Comment convertir un blob en entier en python?

+0

Vous pouvez probablement utiliser le module struct. Quelle est la taille de «N»? –

+0

Copie possible de [Endianness of integers dans Python] (http://stackoverflow.com/questions/1400012/endianness-of-integers-in-python) –

+0

'N' peut être jusqu'à la taille du fichier. – warchantua

Répondre

4

En Python 3 vous pouvez utiliser quelque chose comme ceci:

int.from_bytes(byte_string, byteorder='little') 
+0

Ooooo Je ne le savais pas. +1 –

+0

Ok, nous avons une solution pour Python 3. Comment faire pour Python 2? – warchantua

+0

En utilisant 'struct' comme @ juanpa.arrivillaga a mentionné – dunder

0

En utilisant Python 3 (ou 2), vous pouvez y parvenir avec la bibliothèque struct.

with open('blob.dat', 'rb') as f: 
    data = f.read(n) 

Maintenant, vous déballez en utilisant le format specifier string approprié. Par exemple, big-endian int:

num = struct.unpack(">i",data) 
+0

'struct' est également disponible en Python2, n'est-ce pas? – VPfB

+0

@VPfB Oui. Voir les [docs] (https://docs.python.org/2.7/library/struct.html#module-struct). –

2

Comme le montre la réponse « Harshad Mulmuley, cela est facile en Python 3, en utilisant la méthode int.from_bytes. En Python 2, c'est un peu plus compliqué. Le module struct est conçu pour gérer les types de données C standard. Il ne gérera pas les entiers de longueur arbitraire (entiers Python 2 long), car ils ne sont pas natifs de C. Mais vous pouvez les convertir en utilisant une simple boucle for. Je m'attends à ce que ce soit sensiblement plus lent que le Python 3, puisque les boucles Python for sont plus lentes que la boucle à la vitesse C, comme le fait probablement int.from_bytes.

from binascii import hexlify 

def int_from_bytes_LE(s): 
    total = 0 
    for c in reversed(s): 
     total = (total << 8) + ord(c) 
    return total 

# Test 

data = (
    (b'\x01\x02\x03\x04', 0x04030201), 
    (b'\x01\x02\x03\x04\x05\x06\x07\x08', 0x0807060504030201), 
    (b'\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef', 
     0xefcdab8967452301efcdab8967452301), 
) 

for s, u in data: 
    print hexlify(s), u, int_from_bytes_LE(s) 
    #print(hexlify(s), u, int.from_bytes(s, 'little')) 

sortie

01020304 67305985 67305985 
0102030405060708 578437695752307201 578437695752307201 
abcdefabcdef 318753391026855559389420636404904698625 318753391026855559389420636404904698625 

(je mets que Python 3 appel d'impression là-bas de sorte que vous pouvez facilement vérifier que ma fonction donne le même résultat que int.from_bytes).

Si vos données sont vraiment grand et vous ne voulez pas perdre RAM inverser votre chaîne d'octets vous pouvez le faire de cette façon:

def int_from_bytes_LE(s): 
    m = 1 
    total = 0 
    for c in s: 
     total += m * ord(c) 
     m <<= 8 
    return total 

Bien sûr, qui utilise une RAM pour m, mais il ne sera pas aussi important que la RAM utilisée pour inverser la chaîne d'entrée.