用于将字节写入文件的C struct的Python等效项

jbose2ul  于 2023-01-04  发布在  Python
关注(0)|答案(1)|浏览(119)

以下C代码最简单的Python等价物是什么?

#include <stdio.h>

int main(void) {
    struct dog {
        char breed[16];
        char name[16];
    };
    struct person {
        char name[16];
        int age;
        struct dog pets[2];
    };
    struct person p = {
        "John Doe", 20, {{"Lab", "Foo"}, {"Pug", "Bar"}}
    };
    FILE *fp = fopen("data_from_c.txt", "w");
    fwrite(&p, sizeof(p), 1, fp);
    fclose(fp);
    return 0;
}

我在这里的主要目标是将数据作为连续字节写入文件:

$ xxd data_from_c.txt
00000000: 4a6f 686e 2044 6f65 0000 0000 0000 0000  John Doe........
00000010: 1400 0000 4c61 6200 0000 0000 0000 0000  ....Lab.........
00000020: 0000 0000 466f 6f00 0000 0000 0000 0000  ....Foo.........
00000030: 0000 0000 5075 6700 0000 0000 0000 0000  ....Pug.........
00000040: 0000 0000 4261 7200 0000 0000 0000 0000  ....Bar.........
00000050: 0000 0000                                ....

到目前为止,我已经尝试使用namedtuple s和struct模块来打包Python值:

from collections import namedtuple
import struct

dog = namedtuple('dog', 'breed name')
person = namedtuple('person', 'name age pets')
p = person(
    name=b'John Doe',
    age=22,
    pets=(dog(breed=b'Lab', name=b'Foo'), dog(breed=b'Pug', name=b'Bar'))
)

with open('data_from_python.txt', 'wb') as f:
    b = struct.pack('<16s i 16s 16s 16s 16s', *p)
    f.write(b)

但是,*p解包并不递归地解包可迭代对象,有什么方法可以正确地做到这一点吗?
如果有一种不涉及使用structnamedtuple的替代方法,那也是受欢迎的。

fwzugrvs

fwzugrvs1#

我很想创建PersonDog数据类,并向这些数据类添加方法,以处理将数据打包和解包到字节的操作。
例如:

from dataclasses import dataclass, field
from pathlib import Path
import struct

@dataclass
class Dog:
    breed: str = ''
    name: str = ''
    _fmt: str = field(init=False, repr=False, default='<16s16s')

    def to_bytes(self):
        return struct.pack(self._fmt, self.breed.encode(), self.name.encode())

    def from_bytes(self, bin_data):
        breed, name = struct.unpack(self._fmt, bin_data)
        self.breed = breed.rstrip(b'\x00').decode()
        self.name = name.rstrip(b'\x00').decode()
        return self

@dataclass
class Person:
    name: str = ''
    age: int = 0
    pets: list[Dog] = field(default_factory=list)
    _fmt: str = field(init=False, repr=False, default='<16si')

    def to_bytes(self):
        person_bytes = bytearray()
        person_bytes.extend(struct.pack(self._fmt, self.name.encode(), self.age))
        for pet in self.pets:
            person_bytes.extend(pet.to_bytes())
        return bytes(person_bytes)

    @staticmethod
    def _split_pets(seq, size):
        return (seq[pos:pos + size] for pos in range(0, len(seq), size))

    def from_bytes(self, bin_data: bytes):
        header_size = struct.calcsize(self._fmt)
        dog_size = struct.calcsize(Dog._fmt)
        name, self.age = struct.unpack(self._fmt, bin_data[:header_size])
        self.name = name.rstrip(b'\x00').decode()
        pets_bytes = bin_data[header_size:]

        for pet_data in self._split_pets(pets_bytes, dog_size):
            self.pets.append(Dog().from_bytes(pet_data))
        return self

def main():
    file_loc = Path('/tmp/data_from_python.txt')

    person = Person(
        name='John Doe',
        age=20,
        pets=[
            Dog(breed='Lab', name='Foo'),
            Dog('Pug', 'Bar')
        ])
    file_loc.write_bytes(person.to_bytes())

    # Test recreation of person from file
    new_person = Person().from_bytes(file_loc.read_bytes())
    print("Person from file\n", new_person)

if __name__ == '__main__':
    main()

它给出了文字记录:

Person from file
 Person(name='John Doe', age=20, pets=[Dog(breed='Lab', name='Foo'), Dog(breed='Pug', name='Bar')])

磁盘上的文件看起来与问题中的文件相匹配:

$ xxd /tmp/data_from_python.txt 
00000000: 4a6f 686e 2044 6f65 0000 0000 0000 0000  John Doe........
00000010: 1400 0000 4c61 6200 0000 0000 0000 0000  ....Lab.........
00000020: 0000 0000 466f 6f00 0000 0000 0000 0000  ....Foo.........
00000030: 0000 0000 5075 6700 0000 0000 0000 0000  ....Pug.........
00000040: 0000 0000 4261 7200 0000 0000 0000 0000  ....Bar.........
00000050: 0000 0000                                ....

相关问题