最近接到一个小需求,解读消息服务器的消息日志,因为消息服务器记录消息使用的是二进制方式记录到文件中,需要解析出来并转换为人能看的字符.由于对性能没什么要求,所以选定用python作为主要开发语言,开发一个转换的小工具.这里要用到python的struct模块
消息的格式用结构体描述如下:
struct { uint64_t time; int32_t datalen; vecter<char> protobuf; }
protobuf还需要使用python protobuf进行进一步的解析.
大体处理流程:
1 打开读取二进制文件
2 打开转换后的文件
3 按照结构读取二进制文件
4 每解析一个结构,再解析一次protobuf,将数据还原
5 将一条完整消息追加写入到转换后的文件中
6 重复3-5步直到文件结束
需要说明:
文件的打开
FileObject = open(SrcFile, "rb")
文件的关闭
FileObject.close()
文件的读取
FileObject.read()
文件的写入
FileObject.write()
struct模块操作:
struct模块中最重要的三个函数是:
pack():打包结构图
unpack():解析结构体
calcsize():计算结构体占用的字节数
其中fmt,有一个官方的对照表:
Format | C Type | Python | 字节数 |
x | pad byte | no value | 1 |
c | char | string of length 1 | 1 |
b | signedchar | integer | 1 |
B | unsignedchar | integer | 1 |
? | _Bool | bool | 1 |
h | short | integer | 2 |
H | unsignedshort | integer | 2 |
i | int | integer | 4 |
I | unsignedint | integer or long | 4 |
l | long | integer | 4 |
L | unsignedlong | long | 4 |
q | longlong | long | 8 |
Q | unsignedlonglong | long | 8 |
f | float | float | 4 |
d | double | float | 8 |
s | char[] | string | 1 |
p | char[] | string | 1 |
P | void* | long |
fmt前缀修饰字符表
@ | native | native 凑够4个字节 |
= | native | standard 按原字节数 |
< | little-endian | standard 按原字节数 |
> | big-endian | standard 按原字节数 |
! | network (= big-endian) | standard 按原字节数 |
实现过程
将原有结构体拆分为
struct {
uint64_t time;
int32_t datalen;
} 和 string msg 读取
源码如下:
FileObj = open(ObjFile, "rb")
try:
while True:
BytesRead=FileObj.read(struct.calcsize("=QI"))
if not BytesRead:
break
msgtime, msglen = struct.unpack("=QI",BytesRead)
print "msgtime:",msgtime," msglen:",msglen,
ByteMsg=FileObj.read(msglen)
msgpb = BaseMessage_pb2.basemessage()
msgpb.ParseFromString(ByteMsg)
print " msg:",msgpb.mPayload
finally:
FileObj.close()