2011-10-27 10 views
5

Zwykle wykonuję takie rzeczy w C++, ale używam Pythona do napisania skryptu i natknąłem się na ścianę.Python, jak wstawić 32-bitową liczbę całkowitą do tablicy bajtów

Jeśli mam listę binarną (lub jakikolwiek python przechowuje wynik "fread" w). Mam dostęp do poszczególnych bajtów w nim: buffer [0], buffer [1] itd.

Potrzebuję zmienić bajty [8-11], aby pomieścić nowy 32-bitowy rozmiar pliku (czytaj: tam jest już plik, muszę go zaktualizować). W C++ po prostu dostanę wskaźnik do lokalizacji i wyrzucę go do przechowywania liczby całkowitej, ale pytonem nagle uświadomiłem sobie, że nie mam pojęcia, jak to zrobić.

Jak mogę zaktualizować 4 bajty w moim buforze w określonej lokalizacji, aby zachować wartość liczby całkowitej w python?

EDIT

mam zamiar dodać więcej, bo nie potrafię zrozumieć to od rozwiązań (choć widzę, że jesteśmy na dobrej drodze).

Przede wszystkim jestem w Pythonie 2.4 (i nie mogę uaktualnić dużych serwerów korporacyjnych) - tak więc widocznie ograniczam moje opcje. Przepraszam, że nie wspomniałem o tym wcześniej, nie wiedziałem, że ma tak wiele mniej funkcji.

Po drugie, zróbmy to niezwykle proste.

Powiedzmy, że mam plik binarny o nazwie "myfile.binary" z pięciobajtową zawartością "4C53535353" w języku heksadecymalnym - to odpowiada reprezentacji ASCII dla liter "L i 4xS" będących sam w pliku.

Jeśli zrobić:

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

zawartość powinna (od Sven Marnach za odpowiedź) posiadają pięć-bajtowy ciąg niezmienny.

Używając tylko urządzeń Python 2.4, jak mogę zmienić 4 S przechowywane w "zawartości" na dowolną liczbę całkowitą? To znaczy. daj mi linię kodu, która może sprawić, że zawartość indeksów bajtów [1-4] zawiera 32-bitową liczbę całkowitą "myint" o wartości 12345678910.

+0

nie można zmienić zawartość od napisu jest niezmienny ... możesz cre zjadł nowy ciąg lub użył zmiennego pojemnika jak bytearray. – hochl

+0

Dzięki, jestem szczęśliwy, aby utworzyć nowy ciąg lub tablicę bajtów, jeśli tak jest. W jaki sposób mogę utworzyć modyfikowalną tablicę bajtów z tymi samymi partycjami i zaktualizować zakres [1-4] tej wartości do binarnej reprezentacji mojej liczby całkowitej? –

+0

Rozszerzyłem moją publikację poniżej i dodałem działający przykład dla Pythona 2.4 :-) – hochl

Odpowiedz

8

Co trzeba to ta funkcja:

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

Jest udokumentowane w http://docs.python.org/library/struct.html u góry.

Przykładowy kod:

import struct 
import ctypes 

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

Podobny wpis:Python: How to pack different types of data into a string buffer using struct.pack_into

EDIT: dodał Python 2.4 Przykład kompatybilny:

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. Proponuję użyć wbudowanego 'bytearray' do utworzenia zmiennego bufora zamiast' ctypes.create_string_buffer'. –

+0

** Dla każdego ** spróbowałem go rozwiązać, czytając stronę pakietu i dostarczone rozwiązania. Wydaje się, że brakuje mi dużo, ponieważ mam Pythona 2.4 zamiast 2.5. Dostarczyłem znacznie uproszczoną wersję mojego problemu w edycji do mojego postu powyżej - jeśli możesz odpowiedzieć na to z linią kodu, będę całkowicie zadowolony :) –

+1

Obawiam się, że Twoja wersja zgodna z 2.4 nie może używać ' bytearray', jak to zostało wprowadzone w 2.6. –

4

Zobacz moduł Struct. Potrzebujesz funkcji pack.

EDIT:

Kod:

import struct 

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

wyjściowa:

L╙☻ЦI 

struct.pack powinny być dostępne w pakietempython2.4.

Twój numer "12345678910" nie może być spakowany do 4 bajtów, trochę go skróciłem.

+0

* zobacz komentarz do odpowiedzi hochl * –

+0

zaktualizował odpowiedź –

2

Wynik file.read() jest łańcuchem znaków w języku Python i jest niezmienny. W zależności od kontekstu zadania, które próbujesz wykonać, istnieją różne rozwiązania tego problemu.

Jedną z nich jest array module: Odczytaj plik bezpośrednio jako tablicę 32-bitowych liczb całkowitych. Możesz zmodyfikować tę tablicę i zapisać ją w pliku.

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

* patrz komentarz na odpowiedź hochl * –

2

Mogłeś zainstalować moduł numpy, który jest często używany do obliczeń naukowych.

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

Wtedy dostęp do danych w żądanym miejscu i wprowadź zmiany.

+1

* patrz komentarz na temat odpowiedzi hochl * –

0

Poniżej znajduje się demonstracja, aby zrozumieć, co tak naprawdę dzieje się, gdy cztery bajty są konwertowane na liczbę całkowitą. Załóżmy, że masz numer: 15213

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

W systemach little-endian (tj maszyn x86), liczba ta może być przedstawiona za pomocą długości 4 ByteArray jak: b"\x6d\x3b\x00\x00" lub b"m;\x00\x00" gdy go wydrukować na ekranie, przekształcenie czterech bajtów do liczb całkowitych, po prostu zrobić trochę konwersji bazowej, która w tym przypadku, to:

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

To daje wynik: 15213

Powiązane problemy