版权申明:转载请注明出处。
文章来源:玄涧思库
1.protobuffer简介
protobuffer是google定义的一种文件交换格式,它独立于语言,独立于平台。目前提供了Java、C++、Python等语言实现,用户只需要定义协议文件就可以生成对应语言的源码文件。因其解析速度快,生成的文件占存储小等优点,目前广泛运用于许多项目,如大数据生态圈的YARN,作为其RPC框架的一部分。下面这个案例是将protobuffer用于文件的序列化和反序列化,文件的格式可以自行定义。通过案例充分的感受使用protobuffer进行序列化和反序列化的便利性。
2.背景
在项目中需要和外部进行交换数据,两边使用protobuffer定义了协议。在pb文件的基础上再定义文件格式如下:
(1)文件由数据块组成, 每个数据块包含数据长度和数据区, 数据长度占用 4 字节,使用大端字节序。
(2)数据长度以大端字节序存储。
假设已通过protobuffer生成类DmpData,下面是输出与读入的示例代码。
3.输出
这里需要注意的是连续的文件块其实就是交替的使用DataOutputStream的write方法将存储数据长度的字节数组和存储数据的字节数组写出,其中数据长度都为4字节,数据区根据数据大小不同申请不同的字节空间。
这种结构的文件存储的好处是解析的时候可以先读取数据长度块中存储的数据,说白了就是即将要读取的数据区的字节长度,然后根据这个字节长度去开辟对应的空间读取数据区的内容。代码如下:
//序列化代码
public static void serialize(List<DmpData> datas,String fileName) {
DataOutputStream out = null;
try{
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
for(DmpData data:datas){
//获取序列化大小
int size = data.getSerializedSize();
byte[] net_size = intToByte(size);
byte[] byte_array = data.toByteArray();
//文件写入
out.write(net_size);
out.write(byte_array);
}
}catch(Exception e){
}finally{
try {
out.close();
} catch (IOException e) {
}
}
}
//将整型转换为大端字节序
public static byte[] intToByte(int n){
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(n);
buffer.order(ByteOrder.BIG_ENDIAN);
return buffer.array();
}
4.读入
针对上述文件格式的读入代码如下:
public static void read(String fileName){
File file = new File(fileName);
try {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
while (in.available()>0){
byte[] size_byte = new byte[4];
in.read(size_byte);
int size = byteToInt(size_byte,0);
byte[] data = new byte[size];
in.read(data);
DmpData dm = DmpData.parseFrom(data);
System.out.println(dm.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
//字节数组转整型
public static int byteToInt(byte[] ary, int offset) {
int value;
value = ((ary[offset]&0xFF)
| ((ary[offset+1]<<8) & 0xFF00)
| ((ary[offset+2]<<16)& 0xFF0000)
| ((ary[offset+3]<<24) & 0xFF000000));
return value;
}