struct解析二进制文件实例 - python

1. File format 配置文件 json

{
  "byte_order": "<",
  "person_info": {
    "person_format": {
      "name": "8s",
      "male": "?",
      "age": "H",
      "height": "I",
      "weight": "f",
      "feature_size": "I",
      "feature": null
    },
    "feature": {
      "Strength": "f",
      "Intelligence": "f",
      "Constitution": "f",
      "Dexterity": "f",
      "Mentality": "f"
    }
  }
}

2. python 源码

# -*- coding:utf-8 -*-
from collections import OrderedDict
import struct
import json
import ctypes
import binascii

'''
二进制文件的写入和读取
'''


def read_file(file_path):
    person = []
    file = open(file_path, "rb")
    name = file.read(8)
    name = struct.unpack('<8s', name)[0]
    male = file.read(1)
    male = struct.unpack('<b', male)[0]
    age = file.read(2)
    age = struct.unpack('<H', age)[0]
    height = file.read(4)
    height = int.from_bytes(height, byteorder='little')
    weight = file.read(4)
    weight = struct.unpack('<f', weight)[0]
    feature_size = file.read(4)
    feature_size = int.from_bytes(feature_size, byteorder='little')
    features = []
    for i in range(feature_size // 4):
        feature_value = file.read(4)
        feature_value = struct.unpack('<f', feature_value)[0]
        features.append(feature_value)
    person.append({
        "name": name,
        "male": male,
        "age": age,
        "height": height,
        "weight": weight,
        "feature_size": feature_size,
        "features": features,
    })
    return person


def write_file(file_path, person, features):
    file = open(file_path, "wb")

    # 把字符串的地方转为字节类型,还要先转成utf-8的编码(否则报错string argument without an encoding)
    name = struct.pack('<8s', person['name'].encode('utf-8'))
    file.write(name)
    male = struct.pack('<?', person['male'])
    file.write(male)
    age = struct.pack('<H', person['age'])
    file.write(age)
    height = struct.pack('<I', person['height'])
    file.write(height)
    weight = struct.pack('<f', person['weight'])
    file.write(weight)
    features_size = struct.pack('<I', person['feature_size'])
    file.write(features_size)
    for key, value in features.items():
        feature_value = struct.pack('<f', value)
        file.write(feature_value)
    file.close()


person_info = dict()
person_feature_info = dict()


def get_format(person_json):
    with open(person_json, "r") as f:
        # Starting with Python 3.7, the regular dict became order preserving, so it is no longer necessary
        # to specify collections.OrderedDict for JSON generation and parsing.
        person_info_format_dict = json.load(f)
        print("person info format: {}".format(person_info_format_dict))

    format_byte_order = person_info_format_dict["byte_order"]
    person_info_format = "{}".format(format_byte_order)
    person_info_keys = []
    for k, v in person_info_format_dict["person_info"]["person_format"].items():
        if k == "feature":
            break
        person_info_format = "{}{}".format(person_info_format, v)
        person_info_keys.append(k)
    person_info_format_size = struct.calcsize(person_info_format)
    print("person_info_format: {}, size: {}".format(person_info_format, person_info_format_size))
    person_info["format"] = person_info_format
    person_info["format_size"] = person_info_format_size
    person_info["keys"] = person_info_keys

    person_feature_format = "{}".format(format_byte_order)
    person_feature_keys = []
    for k, v in person_info_format_dict["person_info"]["feature"].items():
        person_feature_format = "{}{}".format(person_feature_format, v)
        person_feature_keys.append(k)
    person_feature_format_size = struct.calcsize(person_feature_format)
    print("person_feature_format: {}, size: {}".format(person_feature_format, person_feature_format_size))
    person_feature_info["format"] = person_feature_format
    person_feature_info["format_size"] = person_feature_format_size
    person_feature_info["keys"] = person_feature_keys


def parse_person_bin(person_bin):
    with open(person_bin, "rb") as f:
        f.seek(0, 0)
        person_info_value_tuple = struct.unpack(person_info["format"], f.read(person_info["format_size"]))
        person_info_values = list(person_info_value_tuple)
        print("person info: {}".format(person_info_values))
        person_info_dict = dict(zip(person_info["keys"], person_info_values))
        print("person info dict: {}".format(person_info_dict))

        f.seek(person_info["format_size"], 0)
        person_feature_value_tuple = struct.unpack(person_feature_info["format"],
                                                   f.read(person_feature_info["format_size"]))
        person_feature_values = list(person_feature_value_tuple)
        print("person feature info: {}".format(person_feature_values))
        person_feature_dict = dict(zip(person_feature_info["keys"], person_feature_values))
        print("person feature dict: {}".format(person_feature_dict))


def write_file_by_buffer(file_path, person, features):
    with open(file_path, "wb") as f:
        person_info_values = list(person.values())
        #avoid struct.error: argument for 's' must be a bytes object
        person_info_values[0] = person_info_values[0].encode('utf-8')
        person_info_values = tuple(person_info_values)
        print("person info values: {}".format(person_info_values))

        print("{} {}".format(person_info["format_size"], person_info["format"]))
        buff = ctypes.create_string_buffer(person_info["format_size"])
        struct.pack_into(person_info["format"], buff, 0, *person_info_values)
        f.write(buff)
        print('Packed Value :', binascii.hexlify(buff))

        features_values = tuple(features.values())
        print("feature values: {}".format(features_values))
        print("{} {}".format(person_feature_info["format_size"], person_feature_info["format"]))
        buff = ctypes.create_string_buffer(person_feature_info["format_size"])
        struct.pack_into(person_feature_info["format"], buff, 0, *features_values)
        f.write(buff)
        print('Packed Value :', binascii.hexlify(buff))


def main():
    person = OrderedDict()
    person.update({'name': 'Jame'})
    person.update({'male': True})
    person.update({'age': 25})
    person.update({'height': 178})
    person.update({'weight': 64.0})
    person.update({'feature_size': 20})
    features = {'Strength': 54.0,  # 力量
                'Intelligence': 78.0,  # 智力
                'Constitution': 32.0,  # 体力
                'Dexterity': 78.0,  # 敏捷
                'Mentality': 53.0  # 精神
                }
    file_path = "./person_info.bin"
    write_file(file_path, person, features)
    print(read_file(file_path))

    get_format("./person.json")
    parse_person_bin(file_path)

    write_file_by_buffer("./person_info_1.bin", person, features)


if __name__ == '__main__':
    main()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值