【问题标题】:How to append int32 data to protobuf JS bytebuffer message如何将 int32 数据附加到 protobuf JS 字节缓冲区消息
【发布时间】:2015-07-28 12:20:31
【问题描述】:

你好 javascript 大师,

我正在尝试使用 javascript 生成一个基于 protobuf 的文件,该文件具有以下结构:

消息大小 | probuff字节|消息大小 | protobuff字节..等

我的想法是我在一个文件中附加多个 protobuf 消息,稍后通过读取消息大小(4 字节整数)来处理它,然后通过读取相应的以下字节来重建 pb 消息,然后解码每个带有 protobuf 的消息。

我已经在 Objective-C 中进行了编码/解码,但我正在努力使用 javascript 做同样的事情。由于代码不言自明,因此在每次迭代中使用 Objc(使用 pod 'ProtocolBuffers', '~> 1.9.8')如下所示:

//configure protobuff, then build.
DataOperationPB * dataOp = [dataOperationBuilder build];
//get its NSData representation
NSData * varBlob = [dataOp data]; //byte string

unsigned int size = (unsigned int)[dataOp serializedSize];
[variablesBlobContainer appendData:[NSMutableData dataWithBytes:&size length:sizeof(size)]];
[variablesBlobContainer appendData:varBlob];

//then we can easily write this to a file with: 
[variablesBlobContainer writeToFile:fileNameWithPath atomically:YES]

如此简单;如果我打开生成的文件,并说第一个 protobuffer 消息的大小为 250,则可以正确看到文件中的初始数据:

以 HEX 格式查看文件的前 4 个字节(偏移量 0):

FA 00 00 00

作为 INT (LITTLE ENDIAN):

250

按预期工作。如果您对这种语言更熟悉,我也可以使用 python 进行解码(为简洁起见,删除了断言):

 file = open(currentPbdFile, 'r')
                    msgSize = file.read(4)
                    msg_len = struct.unpack('<L',msgSize)[0]
                    while msg_len > 0:
                            bufferVar = file.read(msg_len)
                            dataOpList.append(DataOperation(bufferVar))
                            msgSize = file.read(4)

                            if(msgSize == ''):
                                    break
                            msg_len = struct.unpack('<L', msgSize)[0]

现在,在尝试使用 javascript 进行相同操作时,我遇到了困难。我的一项尝试是(使用protobuf.js 对消息进行编码):

var ProtoBuf = dcodeIO.ProtoBuf;
var builder = ProtoBuf.loadProtoFile("DataOperationPB.proto");

var ByteBuffer = dcodeIO.ByteBuffer;
var byteBuffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
var data = new DataOperationPB({
                //(omitted code for setting pb message values)
            });

然后在循环中构建消息并附加数据:

byteBuffer.append(new ByteBuffer().writeInt32(data.calculate()));
byteBuffer.append(data.encode()); //the protobuff data itself

稍后我将数据作为 url 下载按钮提供:

var data = new Blob([new DataView(byteBuffer.toArrayBuffer())], {type: 'application/octet-stream'});

从角度:

this.url = ($window.URL || $window.webkitURL).createObjectURL(data);

当我打开下载的 29 长 protobuff 消息的文件时,前四个字节如下所示:

28 01 38 04

这是完全错误的。

进一步挖掘,我注意到protobuf.js 使用他们自己的 ArrayBuffers 实现(称为ByteBuffer.js),当在浏览器中运行 Javascript 时,它又使用普通的 ArrayBuffers。我不是JS的资深人士,有人可以指出完成上述工作的方向吗?提前感谢您的帮助。

【问题讨论】:

    标签: javascript angularjs protocol-buffers arraybuffer


    【解决方案1】:

    回答我自己的问题.. 库的开发人员帮我弄清楚了。

    我陷入的陷阱是没有注意到 .toArrayBuffer() 方法实际上需要执行读取,并且当从/切换到写入/读取操作时需要使用 flip(),这里:

    //the important, forgotten flip() - 'implicit' read operation:
    new Blob([new DataView(byteBuffer.flip().toArrayBuffer())]
    

    另外,当直接使用 .writeInt32() 时,不需要翻转,而追加一个新创建的 byteBuffer 需要:

    for(...){
        byteBuffer.writeInt32(data.calculate());
        // -- or --
        byteBuffer.append(new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN).writeInt32(data.calculate()).flip());
    }
    

    Here 是关于它的更多文档。希望这对某人有所帮助。

    最好的问候!

    【讨论】:

      猜你喜欢
      • 2017-09-29
      • 2016-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 2012-05-08
      相关资源
      最近更新 更多