最近接到一个小需求,解读消息服务器的消息日志,因为消息服务器记录消息使用的是二进制方式记录到文件中,需要解析出来并转换为人能看的字符.由于对性能没什么要求,所以选定用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()