大家好,
我正在尝试使用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());
}
这里有更多关于它的文档。希望这对大家有所帮助。
致以最亲切的问候!