python通讯和文件打包解包之struct
struct模块中的函数
函数 | return | explain |
---|---|---|
pack(fmt,v1,v2…) | string | 按照给定的格式(fmt),把数据转换成字符串(字节流),并将该字符串返回. |
pack_into(fmt,buffer,offset,v1,v2…) | None | 按照给定的格式(fmt),将数据转换成字符串(字节流),并将字节流写入以offset开始的buffer中.(buffer为可写的缓冲区,可用array模块) |
unpack(fmt,v1,v2……) | tuple | 按照给定的格式(fmt)解析字节流,并返回解析结果 |
pack_from(fmt,buffer,offset) | tuple | 按照给定的格式(fmt)解析以offset开始的缓冲区,并返回解析结果 |
calcsize(fmt) | size of fmt | 计算给定的格式(fmt)占用多少字节的内存,注意对齐方式 |
格式化字符串
当打包或者解包的时,需要按照特定的方式来打包或者解包.该方式就是格式化字符串,它指定了数据类型,除此之外,还有用于控制字节顺序、大小和对齐方式的特殊字符.
对齐方式
为了同c中的结构体交换数据,还要考虑c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下
Character | Byte order | Size | Alignment |
---|---|---|---|
@(默认) | 本机 | 本机 | 本机,凑够4字节 |
= | 本机 | 标准 | none, |
< | 小端 | 标准 | none,按原字节数 |
> | 大端 | 标准 | none,按原字节数 |
! | network(大端) | 标准 | none,按原字节数 |
格式符 | C语言类型 | Python类型 | Standard size |
---|---|---|---|
x | pad byte(填充字节) | no value | |
c | char | string of length 1 | 1 |
b | signed char | integer | 1 |
B | unsigned char | integer | 1 |
? | _Bool | bool | 1 |
h | short | integer | 2 |
H | unsigned short | integer | 2 |
i | int | integer | 4 |
I(大写的i) | unsigned int | integer | 4 |
l(小写的L) | long | integer | 4 |
L | unsigned long | long | 4 |
q | long long | long | 8 |
Q | unsigned long | long long | 8 |
f | float | float | 4 |
d | double | float | 8 |
s | char[] | string | |
p | char[] | string | |
P | void * | long |
import struct
struct.pack('>I', 10240099)struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')
#(4042322160, 32896)
# -*- coding: utf-8 -*-import base64,structbmp_data = base64.b64decode('Qk1oAgAAAAAAADYAAAAoAAAAHAAAAAoAAAABABAAAAAAADICAAASCwAAEgsAAAAAAAAAAAAA/3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9/AHwAfAB8AHwAfAB8AHwAfP9//3//fwB8AHwAfAB8/3//f/9/AHwAfAB8AHz/f/9//3//f/9//38AfAB8AHwAfAB8AHwAfAB8AHz/f/9//38AfAB8/3//f/9//3//fwB8AHz/f/9//3//f/9//3//f/9/AHwAfP9//3//f/9/AHwAfP9//3//fwB8AHz/f/9//3//f/9/AHwAfP9//3//f/9//3//f/9//38AfAB8AHwAfAB8AHwAfP9//3//f/9/AHwAfP9//3//f/9//38AfAB8/3//f/9//3//f/9//3//fwB8AHwAfAB8AHwAfAB8/3//f/9//38AfAB8/3//f/9//3//fwB8AHz/f/9//3//f/9//3//f/9/AHwAfP9//3//f/9/AHwAfP9//3//fwB8AHz/f/9/AHz/f/9/AHwAfP9//38AfP9//3//f/9/AHwAfAB8AHwAfAB8AHwAfAB8/3//f/9/AHwAfP9//38AfAB8AHwAfAB8AHwAfAB8/3//f/9//38AfAB8AHwAfAB8AHwAfAB8/3//f/9/AHwAfAB8AHz/fwB8AHwAfAB8AHwAfAB8AHz/f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//38AAA==')def bmp_info(data):str = struct.unpack('<ccIIIIIIHH',data[:30]) #bytes类也有切片方法if str[0]==b'B' and str[1]==b'M':print("这是位图文件")return {'width': str[-4],'height': str[-3],'color': str[-1]}else:print("这不是位图文件")if __name__ == '__main__':bmp_info(bmp_data)print('ok')
通常的打包和解包
import struct
import binasciivalues = (1, b 'good' , 1.22) #查看格式化对照表可知,字符串必须为字节流类型。
s = struct .Struct( 'I4sf' )
packed_data = s.pack(*values)
unpacked_data = s.unpack(packed_data)print( 'Original values:' , values)
print( 'Format string :' , s.format)
print( 'Uses :' , s.size, 'bytes' )
print( 'Packed Value :' , binascii.hexlify(packed_data))#返回字节流的十六进制字节流
print( 'Unpacked Type :' , type(unpacked_data), ' Value:' , unpacked_data)# 官方文档地址:https://docs.python.org/zh-cn/3/library/struct.html
from struct import *
from collections import namedtuple# 对python整型,打包
print("h:c类型short:",pack('h', 1))
print("l:c类型long:",pack('l', 1))
print("h、l混用结果:",pack('hl', 1, 1)) # h:c类型short,l:c类型long
print("l、h混用结果:",pack('lh', 1, 1))
print("h、h混用结果:",pack('hh', 1, 1))
print("l、l混用结果:",pack('ll', 1, 1))# 对C类型字节,解包
print("对c类型short解包:",unpack('h', b'\x01\x00'))
print("对c类型long解包:",unpack('l', b'\x01\x00\x00\x00'))
print("对h、l混用结果解包:",unpack('hl', b'\x01\x00\x00\x00\x01\x00\x00\x00')) # h:c类型short,l:c类型long
print("对l、h混用结果解包:",unpack('lh', b'\x01\x00\x00\x00\x01\x00'))
print("对h、h混用结果解包:",unpack('hh', b'\x01\x00\x01\x00'))
print("对l、l混用结果解包:",unpack('ll', b'\x01\x00\x00\x00\x01\x00\x00\x00'))# 小结:通过上述操作,发现h、l和l、l的混用打包是一致的,而h、l和l、h打包却不一致。# 解包的字段可通过将它们赋值给变量或将结果包装为一个具名元组来命名:
record = b'raymond \x32\x12\x08\x01\x08' # 前10个是字符串
name, serialnum, school, gradelevel = unpack('<10sHHb', record) # 解包对象是record,<10代表前10个字节作为解包的一部分,s表示字节串char[],H代表unsigned short,b代表signed char
print(name)
print(serialnum)
print(school)
print(gradelevel)
Student01 = namedtuple('Student', 'name serialnum school gradelevel')
print(Student01._make(unpack('<10sHHb', record))) # Student(name=b'raymond ', serialnum=4658, school=264, gradelevel=8)
Student02 = Student01(*unpack('<10sHHb', record)) # 元组赋值方式
print(Student02.serialnum) # 元组取值方式# 格式字符的顺序可能对大小产生影响,因为满足对齐要求所需的填充是不同的:
print(pack('ci', b'*', 0x12131415)) # b'*\x00\x00\x00\x12\x13\x14\x15'
print(pack('ic', 0x12131415, b'*')) # b'\x12\x13\x14\x15*'
print(calcsize('ci')) # 8, 以字节为单位返回格式字符串所描述的结构的大小。
print(calcsize('ic')) # 5# 以下格式 'llh0l' 指定在末尾有两个填充字节,假定 long 类型按 4 个字节的边界对齐:
print(pack('llh0l', 1, 2, 3)) # b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'# Struct(format)对象的使用
obj = Struct("h")
print(obj.pack(1)) # 效果等价于 pack('h', 1)'''等价情况
pack(v1, v2, ...)
等价于 pack() 函数,使用了已编译的格式。 (len(result) 将等于 size。)
pack_into(buffer, offset, v1, v2, ...)
等价于 pack_into() 函数,使用了已编译的格式。
unpack(buffer)
等价于 unpack() 函数,使用了已编译的格式。 缓冲区的字节大小必须等于 size。
unpack_from(buffer, offset=0)
等价于 unpack_from() 函数,使用了已编译的格式。 缓冲区的字节大小从位置 offset 开始必须至少为 size。
iter_unpack(buffer)
等价于 iter_unpack() 函数,使用了已编译的格式。 缓冲区的大小必须为 size 的整数倍。
3.4 新版功能.
format
用于构造此 Struct 对象的格式字符串。
在 3.7 版更改: 格式字符串类型现在是 str 而不再是 bytes。
size
计算出对应于 format 的结构大小(亦即 pack() 方法所产生的字节串对象的大小)。import struct# 打包数据
data_to_send = struct.pack('i 3s f', 123, b'abc', 3.14)# 发送数据到网络
# ...# 接收数据并解包
received_data = b'\x7b\x00\x00\x00abc\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00'
unpacked_data = struct.unpack('i 3s f', received_data)
print(unpacked_data) # 输出:(123, b'abc', 3.14)a = 'hello'
b = a.encode()
print(b)
#b 'hello'
c = binascii.hexlify(b)
print(c)
#b '68656c6c6f'
使用buffer来进行打包和解包
# -*- coding: utf-8 -*-
"" "
通过buffer方式打包和解包
"" "
import struct
import binascii
import ctypesvalues = (1, b 'good' , 1.22) #查看格式化字符串可知,字符串必须为字节流类型。
s = struct .Struct( 'I4sf' )
buff = ctypes.create_string_buffer(s.size)
packed_data = s.pack_into(buff,0,*values)
unpacked_data = s.unpack_from(buff,0)print( 'Original values:' , values)
print( 'Format string :' , s.format)
print( 'buff :' , buff)
print( 'Packed Value :' , binascii.hexlify(buff))
print( 'Unpacked Type :' , type(unpacked_data), ' Value:' , unpacked_data)#结果:#Original values1: (1, b'good', 1.22)
#Original values2: (b'hello', True)
#buff : <ctypes.c_char_Array_18 object at 0x000000D5A5617348>
#Packed Value : b'01000000676f6f64f6289c3f68656c6c6f01'
#Unpacked Type : <class 'tuple'> Value: (1, b'good', 1.2200000286102295)
#Unpacked Type : <class 'tuple'> Value: (b'hello', True)
#[Finished in 0.1s]
使用buffer方式来打包多个对象
# -*- coding: utf-8 -*-
"" "
buffer方式打包和解包多个对象
"" "
import struct
import binascii
import ctypesvalues1 = (1, b 'good' , 1.22) #查看格式化字符串可知,字符串必须为字节流类型。
values2 = (b 'hello' ,True)
s1 = struct .Struct( 'I4sf' )
s2 = struct .Struct( '5s?' )
buff = ctypes.create_string_buffer(s1.size+s2.size)
packed_data_s1 = s1.pack_into(buff,0,*values1)
packed_data_s2 = s2.pack_into(buff,s1.size,*values2)
unpacked_data_s1 = s1.unpack_from(buff,0)
unpacked_data_s2 = s2.unpack_from(buff,s1.size)print( 'Original values1:' , values1)
print( 'Original values2:' , values2)
print( 'buff :' , buff)
print( 'Packed Value :' , binascii.hexlify(buff))
print( 'Unpacked Type :' , type(unpacked_data_s1), ' Value:' , unpacked_data_s1)
print( 'Unpacked Type :' , type(unpacked_data_s2), ' Value:' , unpacked_data_s2)
print(type(‘struct模块’.encode(‘utf-8’)))
print(type(‘struct模块’.encode(‘gbk’)))
print(type(‘struct模块’.encode(‘gb2312’)))
print(type(str(‘struct模块’.encode(‘gb2312’))))
print(type(‘struct模块’.encode(‘gb2312’).decode(‘gb2312’)))
print(type(‘struct模块’))
"""
bytes()是Python3的一个内置函数# coding: utf-8import structt ='查'.encode('gb2312')
print(t)
# tt = struct.unpack('s', t)[0]
tt = t.decode('gb2312')
print(str(tt))
"""
b'\xb2\xe9'
查
"""
i = struct.pack('i', 4)
print(i)
ii = struct.unpack('i', i)
print(ii)
"""
b'\x04\x00\x00\x00'
(4,)
"""
s = struct.pack('ii', 4, 4)
print(s)
ss = struct.unpack('ii', s)
print(ss)
"""
b'\x04\x00\x00\x00\x04\x00\x00\x00'
(4, 4)
"""a = struct.pack('hhl', 1,2,3)
print(a)
b = struct.unpack('hhl', a)
print(b)
"""
b'\x01\x00\x02\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'
(1, 2, 3)
""""""
打包和解包数据
# 打包数据
packed_data = struct.pack('i 3s f', 123, b'abc', 3.14)# 解包数据
unpacked_data = struct.unpack('i 3s f', packed_data)
print(unpacked_data) # 输出:(123, b'abc', 3.140000104904175)
大端序和小端序
# 大端序
big_endian_data = struct.pack('>i', 12345)# 小端序
little_endian_data = struct.pack('<i', 12345)
处理嵌套结构体
# 定义嵌套结构体格式化字符串
nested_format = '2s h'
outer_format = '4s ' + nested_format# 打包嵌套结构体数据
outer_packed_data = struct.pack(outer_format, b'ABCD', b'xy', 123)# 解包嵌套结构体数据
outer_unpacked_data = struct.unpack(outer_format, outer_packed_data)
print(outer_unpacked_data) # 输出:(b'ABCD', b'xy', 123)
struct模块 的应用场景
文件解析
import struct# 读取二进制文件
with open('data.bin', 'rb') as file:binary_data = file.read()# 解包数据
unpacked_data = struct.unpack('i 3s f', binary_data)
print(unpacked_data)
底层系统交互
import struct# 与硬件设备通信,发送和接收二进制数据
# ...# 解析操作系统底层API返回的二进制数据
# ...
处理二进制数据
import struct# 打包加密后的二进制数据
encrypted_data = b'\x7b\x00\x00\x00abc\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00'
packed_data = struct.pack('i 3s f', *struct.unpack('i 3s f', encrypted_data))# 解包解密后的二进制数据
decrypted_data = struct.unpack('i 3s f', packed_data)
print(decrypted_data)## 网络通信
import struct
打包数据
data_to_send = struct.pack(‘i 3s f’, 123, b’abc’, 3.14)
发送数据到网络
…
接收数据并解包
received_data = b'\x7b\x00\x00\x00abc\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00'
unpacked_data = struct.unpack('i 3s f', received_data)
print(unpacked_data) # 输出:(123, b'abc', 3.14)
import os
import struct# 判断文件夹中是否有目标类型图片,没有则返回0
def is_image_file(filename):# 如果不都为空、0、false,则any()返回truereturn any(filename.endswith(extension) for extension in IMG_EXTENSIONS)# 创建图片数据集,存在列表中并返回
def make_dataset(dir):images = []assert os.path.isdir(dir), '%s is not a valid directory' % dir# os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]]) 通过在目录树中游走输出在目录中的文件名,top返回三项(root,dirs,files),分别代表:# 当前正在遍历的这个文件夹的本身的地址; list类型,内容是该文件夹中所有的目录的名字(不包括子目录); list类型,内容是该文件夹中所有的文件(不包括子目录)for root, _, fnames in sorted(os.walk(dir)):for fname in fnames:if is_image_file(fname):# print(fname)# 拼接出图片的地址,并加入到images列表path = os.path.join(root, fname)images.append(path)return imagesdef pack(out_dir, indir, target_folders):# 遍历存放数据集的文件夹for target_folder in target_folders:# 拼接生成存放数据集文件夹的路径curr_indir = os.path.join(indir, target_folder)# 生成的大文件路径(含问文件名)curr_out_file = os.path.join(os.path.join(out_dir, '%s.bigfile' % (target_folder)))image_lists = make_dataset(curr_indir)image_lists.sort()with open(curr_out_file, 'wb') as wfid:# 写入文件数量wfid.write(struct.pack('i', len(image_lists)))for i, img_path in enumerate(image_lists):# 写入文件名称img_name = os.path.basename(img_path)img_name_bytes = img_name.encode('utf-8')wfid.write(struct.pack('i', len(img_name_bytes)))wfid.write(img_name_bytes)# 写入图片数据with open(img_path, 'rb') as img_fid:img_bytes = img_fid.read()wfid.write(struct.pack('i', len(img_bytes)))wfid.write(img_bytes)if i % 1 == 0:print('write %d files done' % i)if __name__ == '__main__':IMG_EXTENSIONS = ['.jpg', '.JPG', '.jpeg', '.JPEG','.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.npy']#打包结果存储位置out_dir = 'C:/Users/Administrator/Desktop/test/bigdata'#待打包文件的文件夹路径indir = 'C:/Users/Administrator/Desktop/test'#存储待打包文件的文件夹名字target_folders = ['image', 'npy']pack(out_dir, indir, target_folders)
# -*- coding:utf-8 -*-
import io
import struct
import os
from PIL import Image
import numpy as npdef unpack(file_path,save_path,flag=1):print('start load bigfile (%0.02f GB) into memory' % (os.path.getsize(file_path) / 1024 / 1024 / 1024))with open(file_path, 'rb') as fid:img_num = struct.unpack('i', fid.read(4))[0]img_names = []img_bytes = []print('find total %d images' % img_num)for i in range(img_num):img_name_len = struct.unpack('i', fid.read(4))[0]img_name = fid.read(img_name_len).decode('utf-8')img_names.append(img_name)img_bytes_len = struct.unpack('i', fid.read(4))[0]img_bytes.append(fid.read(img_bytes_len))if i % 5000 == 0:print('load %d images done' % i)print('load all %d images done' % img_num)# 返回图片名字和图片for index in range(0, len(img_names)):try:if flag == 1: #解包图片类型img = Image.open(io.BytesIO(img_bytes[index])).convert('RGB')path_img = os.path.join(save_path,img_names[index])img.save(path_img)elif flag == 0: #解包npy类型npy= np.load(io.BytesIO(img_bytes[index]))path_npy = os.path.join(save_path,img_names[index])np.save(path_npy,npy)except Exception:print('file read error for index %d: %s' % (index, img_names[index]))if __name__ == '__main__':#打包图片类型后的文件路径filepath1 = 'C:/Users/Administrator/Desktop/test/bigdata/image.bigfile'#解包后图片存储地址save_path1 = 'C:/Users/Administrator/Desktop/test/out1'#打包npy类型后的文件路径filepath2 = 'C:/Users/Administrator/Desktop/test/bigdata/npy.bigfile'#解包后npy存储地址save_path2 = 'C:/Users/Administrator/Desktop/test/out2'##解包图片文件#unpack(filepath1,save_path1,flag=1)#解包npy矩阵文件unpack(filepath2,save_path2,flag=0)
Hex格式说明
– | 格式说明 |
---|---|
Start code | 数据每行都由冒号开头 |
Byte count | 数据长度 1 Byte ,表示本行数据的长度,大值是255 (0xFF). 16 (0x10) 和32 (0x20)是最常用的。 |
Address | 数据地址 2 Byte ,表示Memory数据开始16-bit地址偏移。物理地址通常是有这个偏移加上基地址 |
Record type | 数据类型 1 Byte, 00 ~ 05, 表示不同数据段的含义 |
Data | 具体数据 N Byte ,表示本行中数据字节的数量,它和A说明的数据长度一致 |
Checksum | 比如:0300300002337A1E的计算方法: |
- | 数据和为:03 + 00 + 30 + 00 + 02 + 33 + 7A = E2,这个E2的补码是1E,即这个数据record的补码 |
- | 数据类型详解 |
---|---|
‘00’ | 数据记录:用来记录数据,HEX文件的大部分记录都是数据记录 |
‘01’ | 文件结束记录:用来标识文件结束,放在文件的最后,标识HEX文件的结尾 |
‘02’ | 扩展段地址记录:用来标识扩展段地址的记录 |
‘03’ | 开始段地址记录:开始段地址记录 |
‘04’ | 扩展线性地址记录:用来标识扩展线性地址的记录 |
‘05’ | 开始线性地址记录:开始线性地址记录 |
一旦出现段地址或者线性地址,之后所有数据都要加偏移地址,直到出现一个新的段地址或者线性地址,再重新变更偏移地址。数据物理地址为:线性地址左移16位+段地址左移4位+偏移地址。 |
基地址:0108左移16位à0x01080000;
扩展段地址:12FF左移4位à0x00012FF0;
数据偏移地址:0x0100;
实际物理地址=基地址+扩展段地址+偏移地址=0x010930F0。
实例说明
Notepad++ 打开选,自动识别,根据颜色可以看出HEX的记录格式
看到的是16进制显示的ASCII文本格式
重点讲解下 Record type这个参数:
因为HEX的地址段只有两个字节表示,只能寻址到16位,显然是不够的,所以就有了拓展地址(Record type =4),比如 头行数据:020000040100F9 ,02表示数据段的长度,2个字节;0000是默认填充的,04是Record type,表示后面的两个字节0x0100是拓展地址,也就是32位寻址的高16位,那么下面从第二行开始的地址段都会加上这个高地址段组成真正的刷写地址,比如刷写地址是0x01000000
HEX文件大多数行的 Record type 都是00 ,表示是数据段
HEX文件最后一行的 Record type 都是01 ,表示是结束
:20FFE00040F840F840F840F840F840F840F840F840F840F840F840F840F840F840F840F881
:00000001FF
1
2
HEX View 神器
HEX View 是一款专业的解析S19文件,HEX文件的工具,可以很方便的看出打开文件的Block块,起始地址和地址块的长度等信息
📙CAPL解析HEX文件源码
核心变量解释下:
F_SegmentInfor[10]:用来存放解析HEX文件的Block的信息,一般情况下,刷写文件的地址是不连续的,那么就会分成几个Block块,每个Block块我们要记录下该Block的起止地址,数据大小,因为这是我们UDS 34服务下载的必须数据,这里定义数组大小为10,足够大了,具体有多少个Block块,由变量SegCounter记录
FlsData_BufferArr[0x1FFFFFF]: 这个数组是记录是HEX文件的所有字节,数组大小可由刷写文件具体大小设置,因为这个数组存放的是所有Block块的数据,那么当我下载的时候我怎么区分,去取数据呢,那就是 上面说的结构体中的 dword data_offset;这个变量来控制的,
AllDataBytes:该文件所有的数据字节数。
我为什么没有这样定义 结构体呢?这样分段信息不是更加明确,刷写时取数据也更加方便直观吗?想一想为什么? struct FlsData_Segment
{
byte seg_index;
dword start_address;
dword data_size;
byte FlsData_BufferArr[0x1FFFFFF];
} F_SegmentInfor[10];//暂时定数组为10
Record type等于3/5的情况暂时没遇到,脚本没做处理。
/*@!Encoding:936*/variables
{ dword fileHandle;const dword text_module = 0;const dword binary_module = 1;enum File_Type { file_header, file_data,file_tail };struct FlsData_Segment {byte seg_index;dword start_address;dword data_size;dword data_offset; } F_SegmentInfor[10];//暂时定数组为10long SegCounter; //记录文件被分成多少个段long AllDataBytes; // 文件所有的数据字节数byte FlsData_BufferArr[0x1FFFFFF]; //文件中的所有字节被解析后放在该数组
}on key 'a'
{Flash_Parse_HEX("E:\\merge.hex");}long Flash_Parse_Hex(char f_path[])
{long fileHandle;char tmpBuffer[256]; //逐行读取,每行数据缓存dword i;dword tmpBufferByte; //单块数据块字节数qword OffsetAddress; //扩展线性地址 qword ReAddr; //上一数据行起始地址 dword Len; //HEX每行有效数据字节数dword ReLen; //HEX前一次数据长度dword Addr; //HEX每行起始地址dword Type; //HEX每行类型,有00,01,04四种类型long file_line_num; // 文件有多少行tmpBufferByte = 0;ReAddr = 0;ReLen = 0;SegCounter = 0;fileHandle = OpenFileRead(f_path,text_module);if (fileHandle == 0 ) {write("Failed to open File %s !",f_path);return 0 ;}write("File:%s Opened",f_path);while ( fileGetStringSZ(tmpBuffer,elcount(tmpBuffer),fileHandle)!=0 ){file_line_num++; //数据行计数器//write("file_line_num %d",file_line_num);//write("tmpBuffer %s",tmpBuffer);//判断首字符是否为:号if(tmpBuffer[0] == ':'){ Len = (char2byte(tmpBuffer[1])*0x10+char2byte(tmpBuffer[2])); // 数据长度Addr = char2byte(tmpBuffer[3])*0x1000+char2byte(tmpBuffer[4])*0x100+char2byte(tmpBuffer[5])*0x10+char2byte(tmpBuffer[6]);//偏移地址Addr = (OffsetAddress << 16) | Addr; //完整地址Type = char2byte(tmpBuffer[7])*0x10+char2byte(tmpBuffer[8]); //类型//以下为打印解析的过程,打印解析时候的变量// write("Addr %x",Addr);// write("tmpBufferByte %x",tmpBufferByte);switch(Type){case 0x00: //数据if (abs(Addr -ReAddr) > ReLen ) //判断为新数据块{ if(tmpBufferByte == 0) //是否为首行数据字节数{ F_SegmentInfor[SegCounter].data_offset = 0;F_SegmentInfor[SegCounter].start_address = Addr; //记录新数据块的起始地址}else //不是首行{F_SegmentInfor[SegCounter].data_size = tmpBufferByte; //数据长度 SegCounter++; tmpBufferByte = 0; //重新开始计数F_SegmentInfor[SegCounter].start_address = Addr; //记录新数据块的起始地址F_SegmentInfor[SegCounter].data_offset += tmpBufferByte; //相对数组FlsData_BufferArr的开始索引地址}}for(i = 0; i< Len ; i++){FlsData_BufferArr[AllDataBytes] = (char2byte(tmpBuffer[2*i+9])*0x10+char2byte(tmpBuffer[2*i+10]));AllDataBytes++; //全文件的字节计数器tmpBufferByte ++ ;//当前block的计数器} ReAddr = Addr; //保存当前地址,下一次使用 ReLen = Len; //保存当前长度,下一次使用 break;case 0x04: //扩展线性地址记录OffsetAddress = char2byte(tmpBuffer[9])*0x1000+char2byte(tmpBuffer[10])*0x100+char2byte(tmpBuffer[11])*0x10+char2byte(tmpBuffer[12]); //偏移地址 break;case 0x01: //地址,结束 F_SegmentInfor[SegCounter].data_size = tmpBufferByte; //数据长度F_SegmentInfor[SegCounter].data_offset = AllDataBytes - tmpBufferByte; //相对数组FlsData_BufferArr的开始索引地址 SegCounter++;break; } }}write("文件总行数:%d",file_line_num);write("文件总字节数:%d",AllDataBytes);write("文件总分段数:%d",SegCounter);for(i = 0; i < SegCounter; i++){write("数据块:%d, 起始地址:0x%X, 结束地址:0x%X, 数据长度:%6d字节\r\n", i+1, F_SegmentInfor[i].start_address, F_SegmentInfor[i].start_address + F_SegmentInfor[i].data_size - 1, F_SegmentInfor[i].data_size);}fileClose(fileHandle);return 1 ;
}byte char2byte(char ch)
{byte val;val = 0;if ( ch >= '0' && ch <= '9'){val = ch - '0'; }if ( ch >= 'a' && ch <= 'f'){val = (ch - 'a') + 10; }if ( ch >= 'A' && ch <= 'F'){val = (ch - 'A') + 10; }return val;
}
#include “bin2hex.h”int main(int argc, char *argv[]){RESULT_STATUS res;if (argc != 3){printf(“input para doesn‘t match\r\n”);return -1;}res = BinFile2HexFile(argv[1], argv[2]);switch (res){case RES_OK:printf(“hex file to bin file success!\r\n”);return -1;case RES_BIN_FILE_NOT_EXIST:printf(“bin file doesn’t exist!\r\n”);return -1;case RES_HEX_FILE_PATH_ERROR:printf(“hex file path is error, please check it!\r\n”);return -1;}return 0;}
uint16_t BinFormatEncode(uint8_t *dest, HexFormat *p){uint16_t offset = 0;uint8_t check = 0, num = 0; //:(1) + 长度(2) + 地址(4) + 类型(2)sprintf(&dest[offset], “:%02X%02X%02X%02X”, p-》len, p-》addr[0], p-》addr[1], p-》type);offset += 9; //hex格式流数据指针偏移2check = p-》len + p-》addr[0] + p-》addr[1] + p-》type; //计算校验和while (num 《 p-》len) //当数据长度不为0,继续在之前的hex格式流添加数据{sprintf(&dest[offset], “%02X”, p-》data[num]);check += p-》data[num]; //计算校验和offset += 2; //hex格式数据流数据指针偏移2num++; //下一个字符}check = ~check + 1; //反码+1sprintf(&dest[offset], “%02X”, check);offset += 2;return offset; //返回hex格式数据流的长度}RESULT_STATUS BinFile2HexFile(char *src, char *dest){FILE *src_file, *dest_file;uint16_t tmp;HexFormat gHexFor;uint32_t low_addr = 0, hign_addr = 0;uint8_t buffer_bin[NUMBER_OF_ONE_LINE], buffer_hex[MAX_BUFFER_OF_ONE_LINE];uint32_t src_file_length;uint16_t src_file_quotient, cur_file_page = 0;uint8_t src_file_remainder;src_file = fopen(src, “rb”); //源文件为bin文件,以二进制的形式打开if (!src_file) //这里也是相当于用来检查用户的输入是否准备{return RES_BIN_FILE_NOT_EXIST;}dest_file = fopen(dest, “w”); //目的文件为hex文件,以文本的形式打开if (!dest_file){return RES_HEX_FILE_PATH_ERROR;}fseek(src_file, 0, SEEK_END); //定位到文件末src_file_length = ftell(src_file);fseek(src_file, 0, SEEK_SET); //重新定位到开头,准备开始读取数据src_file_quotient = (uint16_t)(src_file_length / NUMBER_OF_ONE_LINE); //商,需要读取多少次src_file_remainder = (uint8_t)(src_file_length % NUMBER_OF_ONE_LINE); //余数,最后一次需要多少个字符gHexFor.data = buffer_bin; //指向需要转换的bin数据流while (cur_file_page 《 src_file_quotient){fread(buffer_bin, 1, NUMBER_OF_ONE_LINE, src_file);gHexFor.len = NUMBER_OF_ONE_LINE;if ((low_addr & 0xffff0000) != hign_addr && hign_addr != 0) //只有大于64K以后才写入扩展线性地址,第一次一般是没有{hign_addr = low_addr & 0xffff0000;gHexFor.addr[0] = (uint8_t)((hign_addr & 0xff000000) 》》 24);gHexFor.addr[1] = (uint8_t)((hign_addr & 0xff0000) 》》 16);gHexFor.type = 4;gHexFor.len = 0; //记录扩展地址tmp = BinFormatEncode(buffer_hex, &gHexFor);fwrite(buffer_hex, 1, tmp, dest_file);fprintf(dest_file, “\n”); ;}gHexFor.addr[0] = (uint8_t)((low_addr & 0xff00) 》》 8);gHexFor.addr[1] = (uint8_t)(low_addr & 0xff);gHexFor.type = 0; //数据记录tmp = BinFormatEncode(buffer_hex, &gHexFor);fwrite(buffer_hex, 1, tmp, dest_file);fprintf(dest_file, “\n”); ;cur_file_page++;low_addr += NUMBER_OF_ONE_LINE;}if (src_file_remainder != 0) //最后一次读取的个数不为0,这继续读取{fread(buffer_bin, 1, src_file_remainder, src_file);gHexFor.addr[0] = (uint8_t)((low_addr & 0xff00) 》》 8);gHexFor.addr[1] = (uint8_t)(low_addr & 0x00ff);gHexFor.len = src_file_remainder;gHexFor.type = 0; //数据记录tmp = BinFormatEncode(buffer_hex, &gHexFor);fwrite(buffer_hex, 1, tmp, dest_file);fprintf(dest_file, “\n”); ;}gHexFor.addr[0] = 0;gHexFor.addr[1] = 0;gHexFor.type = 1; //结束符gHexFor.len = 0;tmp = BinFormatEncode(buffer_hex, &gHexFor);fwrite(buffer_hex, 1, tmp, dest_file);fprintf(dest_file, “\n”); ;fclose(src_file);fclose(dest_file);return RES_OK;}
#define BIN2HEX_Htypedef unsigned char uint8_t;typedef unsigned short uint16_t;typedef unsigned long uint32_t;/********************************************************************************就是每次读写bin文件N个字节,然后再转化为hex格式流,hex格式流长度计算方式: + 长度 + 地址 + 类型 + N个数据(N 》= 0) + 校验1 + 2 + 4 + 2 + N * 2 + 2********************************************************************************/#define NUMBER_OF_ONE_LINE 0x20#define MAX_BUFFER_OF_ONE_LINE (NUMBER_OF_ONE_LINE * 2 + 11)typedef struct {uint8_t len;uint8_t addr[2];uint8_t type;uint8_t *data;} HexFormat;typedef enum {RES_OK = 0, //操作完成RES_BIN_FILE_NOT_EXIST, //相当于bin文件不存在,包括输入的路径可能存在不正确RES_HEX_FILE_PATH_ERROR //目标文件路径可能输入有误} RESULT_STATUS;RESULT_STATUS BinFile2HexFile(char *src, char *dest);#endif
import structlist_dec = [1, 2, 3, 4, 53, 100, 220, 244, 255]
with open('hexBin.bin', 'wb')as fp:for x in list_dec:a = struct.pack('B', x)fp.write(a)print('done')
Python通过读取文件的开头的字节,判断文件的类型
typeList={# archive"504B0304": "zip","526172211A07": "rar","4D534346": "cab","C77102FD": "cpio","78617221": "xar","7573746172003030": "tar","7573746172202000": "tar","1F8B": "gz","1F9D": "z","1FA0": "z","425A68": "bz2","FD377A585A0000": "xz","04224D18": "lz4","377ABCAF271C": "7z","7801": "zlib","789C": "zlib","78DA": "zlib","5F27A889": "jar","2D6C68352D": "lha","91334846": "hap","EDABEEDB": "rpm","213C6172": "deb","2112": "ain","1A02": "arc1","1A03": "arc2","1A04": "arc3","1A08": "arc4","1A09": "arc5","60EA": "arj","4344303031": "iso",# execute"6465780A": "dex","4D5A5000020": "PE32","4D5A9000030": "MS-DOS","7F454C46": "ELF",# image"FFD8FFE1": "jpg","89504E47": "png","474946383761": "gif","474946383961": "gif","49492A00": "tif", # little endian"4D4D002A": "tif", # big endian"424D": "bmp","41433130": "dwg","38425053": "psd","D7CDC69A": "wmf","01000900": "wmf","02000900": "wmf",# document"3C3F786D6C20": "xml","68746D6C3E": "html","7B5C727466": "rtf","D0CF11E0": "xls/doc","D0CF11E0A1B11AE1": "xls/ole","255044462D": "pdf","44656C69766572792D646174": "eml","0100000058000000": "emf","CFAD12FEC5FD746F": "dbx","2142444E": "pst","5374616E64617264204A": "mdb","FF575043": "wpd","252150532D41646F6265": "eps/ps","E3828596": "pwl","AC9EBD8F": "qdf","458600000600": "qbb","53520100": "srt","774F4646": "woff","774F4632": "woff2",# multimedia"57415645": "wav","41564920": "avi","2E7261FD": "ram", # Real Audio"2E524D46": "rm", # Real Media"000001BA": "mpg","000001B3": "mpg","494433": "mp3","6D6F6F76": "mov","3026B2758E66CF11": "asf","4D546864": "mid","4D4C5649": "mlv"}
def bytes2hex(bytes):num = len(bytes)hexstr = u""for i in range(num):t = u"%x" % bytes[i]if len(t) % 2:hexstr += u"0"hexstr += treturn hexstr.upper()def filetype(file):binfile = open(file, 'rb')type = 'unknown'for hcode in typeList.keys():num_bytes = len(hcode) / 2binfile.seek(0)hbytes = struct.unpack_from("B"*num_bytes, binfile.read(num_bytes))code = bytes2hex(hbytes)if code == hcode:type = typeList[hcode]breakbinfile.close()return typeif __name__ == '__main__':type = filetype("test.pdf")print("file type: ", type)
>>> time.time()
1541234551.9965222
>>> time.localtime()
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=3, tm_hour=16, tm_min=45, tm_sec=37, tm_wday=5, tm_yday=307, tm_isdst=0)
>>> time.ctime()
'Sat Nov 3 16:49:08 2018'
>>> time.asctime()
'Sat Nov 3 16:49:18 2018'
>>> print(time.strftime('%Y-%m-%d %H:%M'))
2018-11-03 16:53
>>> time.strptime('2018-11-03 16:53', '%Y-%m-%d %H:%M')
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=3, tm_hour=16, tm_min=53, tm_sec=0, tm_wday=5, tm_yday=307, tm_isdst=-1)
>>> time.time()
1541234551.9965222
>>> time.localtime()
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=3, tm_hour=16, tm_min=45, tm_sec=37, tm_wday=5, tm_yday=307, tm_isdst=0)
>>> time.ctime()
'Sat Nov 3 16:49:08 2018'
>>> time.asctime()
'Sat Nov 3 16:49:18 2018'
>>> print(time.strftime('%Y-%m-%d %H:%M'))
2018-11-03 16:53
>>> time.strptime('2018-11-03 16:53', '%Y-%m-%d %H:%M')
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=3, tm_hour=16, tm_min=53, tm_sec=0, tm_wday=5, tm_yday=307, tm_isdst=-1)