2011-10-27 21 views
5

Normalmente realizo cosas como esta en C++, pero estoy usando python para escribir un script rápido y me he topado con un muro.Python, cómo poner entero de 32 bits en matriz de bytes

Si tengo una lista binaria (o cualquier pitón almacena el resultado de un "fread"). Puedo acceder a los bytes individuales en él con: buffer [0], buffer [1], etc.

Necesito cambiar los bytes [8-11] para mantener un nuevo tamaño de archivo de 32 bits (léase: ya hay un tamaño de archivo allí, necesito actualizarlo). En C++ solo obtendría un puntero a la ubicación y lo lanzaría para almacenar el entero, pero con Python de repente me di cuenta de que no tenía idea de cómo hacer algo como esto.

¿Cómo puedo actualizar 4 bytes en mi búfer en una ubicación específica para mantener el valor de un entero en python?

EDITAR

Voy a añadir más porque me parece que no puede comprenderlo a partir de las soluciones (aunque puedo ver que están en el camino correcto).

En primer lugar, estoy en Python 2.4 (y no puedo actualizar, servidores de grandes corporaciones), por lo que aparentemente limita mis opciones. Perdón por no mencionar eso antes, no sabía que tenía muchas menos funciones.

En segundo lugar, vamos a hacer esto ultra-simple.

Digamos que tengo un archivo binario denominado 'myfile.binary' con el contenido de cinco bytes '4C53535353' en hexadecimal - esto equivale a las representaciones ASCII para las letras "L y 4xS" estar solo en el archivo.

Si hago:

f = open('myfile.binary', 'rb') 
contents = f.read(5) 

contenidos deberían (de la respuesta de Sven Marnach) mantener una cadena inmutable de cinco bytes.

Usando únicamente las instalaciones de Python 2.4, ¿cómo podría cambiar las 4 S contenidas en 'contenidos' a un valor entero arbitrario? Es decir. Dame una línea de código que puede hacer que los índices de byte contenidos [1-4] contengan el entero de 32 bits 'myint' con el valor 12345678910.

+0

no se puede cambiar el contenido ya que la cadena es inmutable ... puedes crear comió una nueva cuerda, o usó un contenedor mutable como bytearray. – hochl

+0

Gracias, me complace crear una nueva cadena o conjunto de bytes si ese es el caso. ¿Cómo podría crear una matriz de bytes modificable con las mismas curvas y actualizar el rango [1-4] de esa para igualar la representación binaria de mi entero? –

+0

Amplié mi publicación a continuación e incluí un ejemplo de trabajo para Python 2.4 :-) – hochl

Respuesta

8

Lo que se necesita es esta función:

struct.pack_into(fmt, buffer, offset, v1, v2, ...) 

Está documentado en http://docs.python.org/library/struct.html cerca de la parte superior.

código

Ejemplo:

import struct 
import ctypes 

data=ctypes.create_string_buffer(10) 
struct.pack_into(">i", data, 5, 0x12345678) 
print list(data) 

publicación similar:Python: How to pack different types of data into a string buffer using struct.pack_into

EDIT: añadido un Python 2.4 ejemplo compatibles:

import struct 

f=open('myfile.binary', 'rb') 
contents=f.read(5) 
data=list(contents) 
data[0:4]=struct.pack(">i", 0x12345678) 
print data 
+1

+1. Sugeriría usar el 'bytearray' incorporado para crear el búfer mutable en lugar de' ctypes.create_string_buffer'. –

+0

** Para todos ** Intenté resolverlo leyendo la página del paquete y las soluciones proporcionadas. Parece que me falta mucho ya que tengo Python 2.4 en vez de 2.5. Proporcioné una versión muy simplificada de mi problema en una edición de mi publicación anterior; si puede responder eso con una línea de código, estaré completamente feliz :) –

+1

Me temo que su versión compatible con 2.4 no puede usar ' bytearray' como se introdujo en 2.6. –

4

Echa un vistazo al módulo Struct. Necesita la función pack.

EDIT:

El código:

import struct 

s = "LSSSS" # your string 
s = s[0] + struct.pack('<I', 1234567891) # note "shorter" constant than in your example 
print s 

Salida:

L╙☻ЦI 

struct.pack debería estar disponible en python2.4.

Su número "12345678910" no se puede empaquetar en 4 bytes, lo acorté un poco.

+0

* ver comentario en la respuesta de hochl * –

+0

actualizó la respuesta –

2

El resultado de file.read() es una cadena en Python, y es inmutable. Dependiendo del contexto de la tarea que está tratando de lograr, existen diferentes soluciones al problema.

Uno está utilizando el array module: lea el archivo directamente como una matriz de enteros de 32 bits. Puede modificar esta matriz y volver a escribirla en el archivo.

with open("filename") as f: 
    f.seek(0, 2) 
    size = f.tell() 
    f.seek(0) 
    data = array.array("i") 
    assert data.itemsize == 4 
    data.fromfile(f, size // 4) 
data[2] = new_value 
# use data.tofile(g) to write the data back to a new file g 
+1

* ver comentario en la respuesta de hochl * –

2

Se podría instalar el módulo numpy, que se usa a menudo para la informática científica.

read_data = numpy.fromfile (archivo = id, dtype = numpy.uint32)

luego acceder a los datos en la ubicación deseada y realice los cambios.

+1

* ver comentario en la respuesta de hochl * –

0

La siguiente es solo una demostración para que entiendas lo que realmente sucede cuando los cuatro bytes se convierten en un entero. Suponga que tiene un número: 15213

Decimal: 15213 
Binary: 0011 1011 0110 1101 
Hex: 3 B 6 D 

En los sistemas poco-endian (es decir, máquinas x86), este número puede ser representado usando un bytearray longitud-4 como: b"\x6d\x3b\x00\x00" o b"m;\x00\x00" cuando se imprime en la pantalla, para convertir los cuatro bytes en un entero, simplemente hacer un poco de conversión de base, que en este caso, es:

sum(n*(256**i) for i,n in enumerate(b"\x6d\x3b\x00\x00")) 

esto le da el resultado: 15213

Cuestiones relacionadas