Как правильно дополнить числа в структуре Python - PullRequest
1 голос
/ 05 октября 2019

У меня есть такой кортеж (обратите внимание, что первый элемент может быть любого размера (большой, но не очень большой, т. Е. 2 ​​** 12 - 1 в порядке), а второй всегда будет в диапазоне [0, 255]).

t = [(0, 137), (0, 80), (0, 78), (0, 71), (0, 13), ...]

Я хочу сохранить эти числа в байтах в файловой системе (для сжатия). Это означает, что я также хочу позже использовать эти биты для восстановления кортежа. Также обратите внимание, что это требование, что используется Big Endian.

for idx, v in compressed:              
    if v:                              
        f.write(struct.pack(">I", idx))
        f.write(struct.pack(">I", v))  

Однако, когда я пытаюсь получить числа, например:

with open(filepath, 'rb') as file:          
    data = file.read(4)                     
    nums = []                               
    while data:                             
        num = struct.unpack(">I", data)[0]  
        print(num)                          
        data = file.read(4)                 
        nums.append(num)                    

Я не получаючисла выше (я для некоторых чисел, но позже это испортится, вероятно, из-за дополнения битов).

Как остаться совместимым с дополнением битов? Как я могу добавить что-то с struct.pack('>I, ...), которое позже смогу надежно получить?

Обновление:

Для следующего набора [(0, 137), (0, 80), (0, 78), (0, 71), (0, 13), (0, 10), (0, 26), (6, 0), (0, 0), (9, 13), (0, 73), (0, 72), (0, 68), (0, 82), (9, 0), (0, 1), (0, 44), (15, 1), (17, 8), (0, 2), (15, 0), (0, 246) ...]

Я получаю следующие числа, используя свойподход:

[0, 137, 0, 80, 0, 78, 0, 71, 0, 13, 0, 10, 0, 26, 9, 13, 0, 73, 0, 72, 0, 68, 0, 82, 0, 1, 0, 44, 15, 1, 17, 8, 0, 2, 0, 246 ...]

Смотрите, в точке (6,0) она начинает расходиться. До этого все нормально. Но это исправляет себя ?? на 9,13 и продолжает хорошо.

Ответы [ 2 ]

1 голос
/ 05 октября 2019

С учетом следующего ввода:

compressed = [(0, 137), (0, 80), (0, 78), (0, 71), (0, 13), (0, 10), (0, 26), (6, 0), (0, 0), (9, 13), (0, 73), (0, 72), (0, 68), (0, 82), (9, 0), (0, 1), (0, 44), (15, 1), (17, 8), (0, 2), (15, 0), (0, 246)]

попробуйте этот код для записи данных:

import struct

with open('file.dat', 'wb') as f:
    for idx, v in compressed:   
        f.write(struct.pack(">I", idx))
        f.write(struct.pack(">I", v)) 

и этот код для чтения:

with open('file.dat', 'rb') as f:
    data = f.read(4)                     
    nums = []
    while data:     
        idx = struct.unpack(">I", data)[0]  
        data = f.read(4)      
        v = struct.unpack(">I", data)[0]
        data = f.read(4)      
        nums.append((idx,v)) 

и nums содержит:

[(0, 137), (0, 80), (0, 78), (0, 71), (0, 13), (0, 10), (0, 26), (6, 0), (0, 0), (9, 13), (0, 73), (0, 72), (0, 68), (0, 82), (9, 0), (0, 1), (0, 44), (15, 1), (17, 8), (0, 2), (15, 0), (0, 246)]

Что совпадает с вводом, на самом деле nums == compressed дает True.

0 голосов
/ 05 октября 2019

Ваш код работает нормально. Тем не менее, у вас есть следующая строка:

if v:

v будет False для некоторых из тех кортежей, где второй элемент - 0, который не будет записан в файли, следовательно, вы не увидите их при чтении из этого файла, опять же.


Кроме того, поскольку вы в любом случае записываете свои элементы попарно, вы можете использовать >II в качестве формата:

from struct import pack, unpack, calcsize

original = [(0, 137), (0, 80), (0, 78), (0, 71), (0, 13), (0, 10), (0, 26), (6, 0), (0, 0), (9, 13), (0, 73), (0, 72), (0, 68), (0, 82), (9, 0), (0, 1), (0, 44), (15, 1), (17, 8), (0, 2), (15, 0), (0, 246)]

filename = "test.txt"
fileformat = ">II"

with open(filename, "wb") as fp:
    for element in original:
        fp.write(pack(fileformat, *element))

with open(filename, "rb") as fp:
    elements = iter(lambda: fp.read(calcsize(fileformat)), b"")
    readback = [unpack(fileformat, element) for element in elements]

print(readback == original)
...