天天看點

Proto3序列化數到檔案與反序列化一、多消息持續序列化規則二、定義proto資料結構三、序列化測試四、反序列化

proto3序列化很好用,在原來開發APP存資料到日志時,日志文檔半小時可達300M,資料量大時對性能有很大影響,是以改用proto序列化存儲資料,經測試性能有所提升,日志大小為原來三分之一,是以優勢還是很明顯的。

但proto3序列化多條消息到檔案時,按官方文檔介紹,反序列化時是沒法區分一個完整對象序列化資料的界限的,也就是沒有分隔符,是以需要自己設定分隔符,反序列化時按規則解即可,以下是基于上一篇文章中環境的案例

一、多消息持續序列化規則

每個對象序列化後位元組數的長度作為序列化内容前置4個位元組的資料,即若一條序列化資料長度為100個位元組,那麼前這個資料前加4個位元組,這4個位元組的内容是100,那麼總長度就是104個位元組,依此規則持續序列化到檔案即可

二、定義proto資料結構

syntax = "proto3";
package tutorial;

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
  string phone = 4;
}
           

三、序列化測試

/**
     * 序列化
     *
     * @param path
     */
    private void serializeProto(String path) {
        System.out.println("serialize file " + path);
        try {
            OutputStream outputStream = new FileOutputStream(new File(path));
            byte[] data;
            for (int i = 0; i < 10; i++) {
                Message.Person person = Message.Person.newBuilder().setId(i)
                        .setEmail(String.valueOf(i)).setName(String.valueOf(i)).setPhone(String.valueOf(i)).build();
                byte[] dataByte = person.toByteArray();
                byte[] lenByte = ProtoHelper.intToByteArray(dataByte.length);

                data = new byte[dataByte.length + lenByte.length];
                System.arraycopy(lenByte, 0, data, 0, lenByte.length);
                System.arraycopy(dataByte, 0, data, lenByte.length, dataByte.length);

                outputStream.write(data);
                System.out.println("serialize len :" + dataByte.length + ",id:" + person.getId() + ",name:" + person.getName() + ",email:" + person.getEmail() + ",phone:" + person.getPhone());
            }
            outputStream.flush();
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }           

四、反序列化

因為上述資料量小,這裡一次性從檔案讀出來,就沒有設定緩沖區了

/**
     * 反序列化
     * @param path
     */
    public void deSerializeProto(String path) {
        System.out.println("deSerialize file " + path);
        try {
            InputStream inputStream = new FileInputStream(new File(path));

            byte[] data = new byte[4096];
            int len = 0;
            while ((len = inputStream.read(data)) > 0) {
                int index = 0;
                while (index < len) {
                    byte[] lenByte = new byte[4];
                    System.arraycopy(data, index, lenByte, 0, 4);
                    int itemLen = ProtoHelper.byteArrayToInt(lenByte);
                    byte[] dataByte = new byte[itemLen];
                    System.arraycopy(data, index + lenByte.length, dataByte, 0, itemLen);

                    Message.Person person = Message.Person.parseFrom(dataByte);
                    System.out.println("deSerialize len :" + (dataByte.length + 4) + ",id:" + person.getId() + ",name:" + person.getName() + ",email:" + person.getEmail() + ",phone:" + person.getPhone());
                    index = index + lenByte.length + dataByte.length;
                }

            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }           

執行結果:

Proto3序列化數到檔案與反序列化一、多消息持續序列化規則二、定義proto資料結構三、序列化測試四、反序列化

由于proto跨平台,是以java端序列化後,C端同僚也能解碼檔案,有一定的日志安全性吧