如何将int32数据附加到protobuf JS字节缓冲区消息



大家好,

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

messageSize | probuff bytes | messageSize | protobuff bytes ..等

这个想法是我在一个文件中附加多个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,谁能请指出的方向,以完成上述?谢谢你的帮助。

回答我自己的问题…这个库的开发者帮我解决了这个问题。

我遇到的陷阱是没有注意到。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());
}

这里有更多关于它的文档。希望这对大家有所帮助。

致以最亲切的问候!

最新更新