18

私は、バイト ストリームにシリアル化された複数の異なる protobuf メッセージで構成される spinn3r からのデータを使用しています。

http://code.google.com/p/spinn3r-client/wiki/Protostream

「プロトストリームはプロトコル バッファ メッセージのストリームであり、Google プロトコル バッファ仕様に従って長さの前に varint を付けてネットワーク上でエンコードされます。ストリームには、ヘッダー、ペイロード、テール マーカーの 3 つの部分があります。」

これは、protobuf のかなり標準的な使用例のようです。実際、protobuf コア ディストリビューションは、C++ と Java の両方に CodedInputStream を提供します。しかし、protobuf は python 用のそのようなツールを提供していないようです。「内部」ツールは、この種の外部使用のために設定されていません。

https://groups.google.com/forum/?fromgroups#!topic/protobuf/xgmUqXVsK-o

だから...私が行く前に、さまざまなメッセージタイプのストリームを解析するためのpython varintパーサーとツールをまとめます:誰かがこれのためのツールを知っていますか?

protobuf にないのはなぜですか? (それとも、単に見つけられなかったのでしょうか?)

これは、特に「トランスポート」と「プロトコル」の両方に対応する thrift の同等のツールと比較すると、protobuf の大きなギャップのように思えます。私はそれを正しく見ていますか?

4

3 に答える 3

15

他の回答のコードがhereから持ち上げられる可能性があるようです。varint32このファイルを使用する前にライセンスを確認しますが、次のようなコードを使用して s を読み取ることができました。

import sys
import myprotocol_pb2 as proto
import varint # (this is the varint.py file)

data = open("filename.bin", "rb").read() # read file as string
decoder = varint.decodeVarint32          # get a varint32 decoder
                                         # others are available in varint.py

next_pos, pos = 0, 0
while pos < len(data):
    msg = proto.Msg()                    # your message type
    next_pos, pos = decoder(data, pos)
    msg.ParseFromString(data[pos:pos + next_pos])

    # use parsed message

    pos += next_pos
print "done!"

varint32これは、次のメッセージのサイズを表す s で区切られた単一タイプのメッセージをロードするように設計された非常に単純なコードです。


更新: 次を使用して、このファイルを protobuf ライブラリから直接インクルードすることもできます。

from google.protobuf.internal.decoder import _DecodeVarint32
于 2014-02-14T07:08:59.380 に答える
-3

これは非常に単純なので、再利用可能なツールを作成するのに誰も気にしない理由がわかります。

'''
Parses multiple protobuf messages from a stream of spinn3r data
'''

import sys
sys.path.append('python_proto/src')
import spinn3rApi_pb2
import protoStream_pb2

data = open('8mny44bs6tYqfnofg0ELPg.protostream').read()

def _VarintDecoder(mask):
    '''Like _VarintDecoder() but decodes signed values.'''

    local_ord = ord
    def DecodeVarint(buffer, pos):
        result = 0
        shift = 0
        while 1:
            b = local_ord(buffer[pos])
            result |= ((b & 0x7f) << shift)
            pos += 1
            if not (b & 0x80):
                if result > 0x7fffffffffffffff:
                    result -= (1 << 64)
                    result |= ~mask
                else:
                    result &= mask
                return (result, pos)
            shift += 7
            if shift >= 64:
                ## need to create (and also catch) this exception class...
                raise _DecodeError('Too many bytes when decoding varint.')
    return DecodeVarint

## get a 64bit varint decoder
decoder = _VarintDecoder((1<<64) - 1)

## get the three types of protobuf messages we expect to see
header    = protoStream_pb2.ProtoStreamHeader()
delimiter = protoStream_pb2.ProtoStreamDelimiter()
entry     = spinn3rApi_pb2.Entry()

## get the header
pos = 0
next_pos, pos = decoder(data, pos)
header.ParseFromString(data[pos:pos + next_pos])
## should check its contents

while 1:
    pos += next_pos
    next_pos, pos = decoder(data, pos)
    delimiter.ParseFromString(data[pos:pos + next_pos])

    if delimiter.delimiter_type == delimiter.END:
        break

    pos += next_pos
    next_pos, pos = decoder(data, pos)
    entry.ParseFromString(data[pos:pos + next_pos])
    print entry
于 2012-07-15T01:34:46.633 に答える