精华内容
下载资源
问答
  • protobuf之string bytes的区别

    万次阅读 2017-09-22 11:58:41
    转自:...protobuf提供了多种基础数据格式,包括string/bytes。从字面意义上,我们了解bytes适用于任意的二进制字节序列。然而对C++程序员来讲,std::string既能存储ASCII文本字符串,也能存储任意

    转自:http://izualzhy.cn/c/cpp/2017/03/20/protobuf-difference-between-string-and-bytes


    protobuf提供了多种基础数据格式,包括string/bytes。从字面意义上,我们了解bytes适用于任意的二进制字节序列。然而对C++程序员来讲,std::string既能存储ASCII文本字符串,也能存储任意多个\0的二进制序列。那么区别在哪里呢?

    同时在实际使用中,我们偶尔会看到类似这样的运行错误:

    [libprotobuf ERROR google/protobuf/wire_format.cc:1091] String field 'str' contains invalid UTF-8 data when serializing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes. 
    [libprotobuf ERROR google/protobuf/wire_format.cc:1091] String field 'str' contains invalid UTF-8 data when parsing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes. 
    

    这篇文章从源码角度分析下string/bytes类型的区别。

    之前的文章里介绍过protobuf序列化的过程,我们看下string/bytes序列化的过程。 在之前的文章里介绍过protobuf序列化的过程,我们看下string/bytes序列化的过程。

    所有的序列化操作都会在SerializeFieldWithCachedSizes这个函数里进行。根据不同的类型调用对应的序列化函数,例如对于string类型

          case FieldDescriptor::TYPE_STRING: {
            string scratch;
            const string& value = field->is_repeated() ?
              message_reflection->GetRepeatedStringReference(
                message, field, j, &scratch) :
              message_reflection->GetStringReference(message, field, &scratch);
            VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
                                       field->name().c_str());
            WireFormatLite::WriteString(field->number(), value, output);
            break;
          }
    

    而对于bytes类型:

          case FieldDescriptor::TYPE_BYTES: {
            string scratch;
            const string& value = field->is_repeated() ?
              message_reflection->GetRepeatedStringReference(
                message, field, j, &scratch) :
              message_reflection->GetStringReference(message, field, &scratch);
            WireFormatLite::WriteBytes(field->number(), value, output);
            break;
          }
    

    可以看到在序列化时主要有两点区别:

    1. string类型调用了VerifyUTF8StringNamedField函数
    2. 序列化函数不同:WriteString vs WriteBytes

    关于第二点,两个函数都定义在wire_format_lite.cc,实现是相同的。

    那么我们继续看下第一点,VerifyUTF8StringNamedField调用了VerifyUTF8StringFallback(话说一直不理解fallback在这里什么意思,protobuf源码里经常看到这个后缀)。看下这个函数的实现:

    
    void WireFormat::VerifyUTF8StringFallback(const char* data,
                                              int size,
                                              Operation op,
                                              const char* field_name) {
      if (!IsStructurallyValidUTF8(data, size)) {
        const char* operation_str = NULL;
        switch (op) {
          case PARSE:
            operation_str = "parsing";
            break;
          case SERIALIZE: 
            operation_str = "serializing";
            break;
          // no default case: have the compiler warn if a case is not covered.
        }
        string quoted_field_name = "";
        if (field_name != NULL) {
          quoted_field_name = StringPrintf(" '%s'", field_name);
        }
        // no space below to avoid double space when the field name is missing.
        GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid "
                   << "UTF-8 data when " << operation_str << " a protocol "
                   << "buffer. Use the 'bytes' type if you intend to send raw "
                   << "bytes. ";
      }
    }
    

    运行错误是从这里输出的,关键还是在于IsStructurallyValidUTF8这个函数,实现在structurally_valid.cc里:

    bool IsStructurallyValidUTF8(const char* buf, int len) {
      if (!module_initialized_) return true;
      
      int bytes_consumed = 0;
      UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
                               buf, len, &bytes_consumed);
      return (bytes_consumed == len);
    }
    

    这里逐个字符扫描是否符合utf-8规范,比如110xxxxx 10xxxxxx这样,具体可以参考utf-8的编码标准。

    反序列化过程类似。

    看到这里我们可以得到这样的结论:

    1. protobuf里的string/bytes在C++接口里实现上都是std::string
    2. 两者序列化、反序列化格式上一致,不过对于string格式,会有一个utf-8格式的检查。

    出于效率,我们应当在确定字段编码格式后直接使用bytes,减少utf8编码的判断,效率上会有提高。

    注意以上代码在pb2.6下,2.4不会输出field_name

    据了解java接口上有一定的区别,分别对应String以及ByteString


    展开全文
  • protobuf string/bytes

    千次阅读 2018-08-01 14:35:01
    protobuf提供了多种基础数据格式,包括string/bytes。从字面意义上,我们了解bytes适用于任意的二进制字节序列。然而对C++程序员来讲,std::string既能存储ASCII文本字符串,也能存储任意多个\0的二进制序列。那么...

    protobuf提供了多种基础数据格式,包括string/bytes。从字面意义上,我们了解bytes适用于任意的二进制字节序列。然而对C++程序员来讲,std::string既能存储ASCII文本字符串,也能存储任意多个\0的二进制序列。那么区别在哪里呢?

    同时在实际使用中,我们偶尔会看到类似这样的运行错误:

     
    1. [libprotobuf ERROR google/protobuf/wire_format.cc:1091] String field 'str' contains invalid UTF-8 data when serializing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes.

    2. [libprotobuf ERROR google/protobuf/wire_format.cc:1091] String field 'str' contains invalid UTF-8 data when parsing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes.

    这篇文章从源码角度分析下string/bytes类型的区别。

    之前的文章里介绍过protobuf序列化的过程,我们看下string/bytes序列化的过程。 在之前的文章里介绍过protobuf序列化的过程,我们看下string/bytes序列化的过程。

    所有的序列化操作都会在SerializeFieldWithCachedSizes这个函数里进行。根据不同的类型调用对应的序列化函数,例如对于string类型

     
    1. case FieldDescriptor::TYPE_STRING: {

    2. string scratch;

    3. const string& value = field->is_repeated() ?

    4. message_reflection->GetRepeatedStringReference(

    5. message, field, j, &scratch) :

    6. message_reflection->GetStringReference(message, field, &scratch);

    7. VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,

    8. field->name().c_str());

    9. WireFormatLite::WriteString(field->number(), value, output);

    10. break;

    11. }

    而对于bytes类型:

     
    1. case FieldDescriptor::TYPE_BYTES: {

    2. string scratch;

    3. const string& value = field->is_repeated() ?

    4. message_reflection->GetRepeatedStringReference(

    5. message, field, j, &scratch) :

    6. message_reflection->GetStringReference(message, field, &scratch);

    7. WireFormatLite::WriteBytes(field->number(), value, output);

    8. break;

    9. }

    可以看到在序列化时主要有两点区别:

    1. string类型调用了VerifyUTF8StringNamedField函数
    2. 序列化函数不同:WriteString vs WriteBytes

    关于第二点,两个函数都定义在wire_format_lite.cc,实现是相同的。

    那么我们继续看下第一点,VerifyUTF8StringNamedField调用了VerifyUTF8StringFallback(话说一直不理解fallback在这里什么意思,protobuf源码里经常看到这个后缀)。看下这个函数的实现:

     
    1.  
    2. void WireFormat::VerifyUTF8StringFallback(const char* data,

    3. int size,

    4. Operation op,

    5. const char* field_name) {

    6. if (!IsStructurallyValidUTF8(data, size)) {

    7. const char* operation_str = NULL;

    8. switch (op) {

    9. case PARSE:

    10. operation_str = "parsing";

    11. break;

    12. case SERIALIZE:

    13. operation_str = "serializing";

    14. break;

    15. // no default case: have the compiler warn if a case is not covered.

    16. }

    17. string quoted_field_name = "";

    18. if (field_name != NULL) {

    19. quoted_field_name = StringPrintf(" '%s'", field_name);

    20. }

    21. // no space below to avoid double space when the field name is missing.

    22. GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid "

    23. << "UTF-8 data when " << operation_str << " a protocol "

    24. << "buffer. Use the 'bytes' type if you intend to send raw "

    25. << "bytes. ";

    26. }

    27. }

    运行错误是从这里输出的,关键还是在于IsStructurallyValidUTF8这个函数,实现在structurally_valid.cc里:

     
    1. bool IsStructurallyValidUTF8(const char* buf, int len) {

    2. if (!module_initialized_) return true;

    3.  
    4. int bytes_consumed = 0;

    5. UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,

    6. buf, len, &bytes_consumed);

    7. return (bytes_consumed == len);

    8. }

    这里逐个字符扫描是否符合utf-8规范,比如110xxxxx 10xxxxxx这样,具体可以参考utf-8的编码标准。

    反序列化过程类似。

    看到这里我们可以得到这样的结论:

    1. protobuf里的string/bytes在C++接口里实现上都是std::string
    2. 两者序列化、反序列化格式上一致,不过对于string格式,会有一个utf-8格式的检查。

    出于效率,我们应当在确定字段编码格式后直接使用bytes,减少utf8编码的判断,效率上会有提高。

    注意以上代码在pb2.6下,2.4不会输出field_name

    据了解java接口上有一定的区别,分别对应String以及ByteString

    展开全文
  • 在用proto协议的系统中,写自测用具用到json转pb的函数,但是如果proto协议中有bytes字段,纯json转pb就会报错,以下函数返回false ...参考:https://github.com/protocolbuffers/protobuf/issues/5719https://github

    在用proto协议的系统中,写自测用具用到json转pb的函数,但是如果proto协议中有bytes字段,纯json转pb就会报错,以下函数返回false

    JsonStringToMessage(test_msg, &message).ok()

    查资料发现bytes 字段要先进行base64编码,再放到json里,这样就能成功解析成pb对象了。

    参考:https://github.com/protocolbuffers/protobuf/issues/5719icon-default.png?t=L892https://github.com/protocolbuffers/protobuf/issues/5719

    展开全文
  • 如何将Java中的byte转为protobufbytes

    千次阅读 2019-01-19 14:19:30
    Java中的byte转为protobufbytes   在protobuf中如果定义了bytes类型的消息传输对象 syntax = &amp;quot;proto3&amp;quot;; option java_package=&amp;quot;com.test.protobuf&amp;quot;; ...

    Java中的byte转为protobuf中bytes

      在protobuf中如果定义了bytes类型的消息传输对象

    	syntax = "proto3";
    	option java_package="com.test.protobuf";
    	option java_outer_classname = "NettyMessage";
    	message MessageBase {
    		 bytes data =1;
    	}
    

      在生成protobuf 的java类后,bytes会变成ByteString类型

    	// protobuf 生成的java代码中的一小段
    	 public Builder setData(com.google.protobuf.ByteString value) {
    	 }
    

      如果想在java代码中,传输byte类型的数据。直接将byte类型的数据放入protobuf定义的bytes类型的对象中是不可行的,需要通过protobuf的API再进行转化一下。

    	MessageBase.Builder messageBase = MessageBase.newBuilder();
    	byte[] b = new byte[10];
    	messageBase.setData(ByteString.copyFrom(b));
    

      ByteString.copyFrom(byte[] bytes)这个API可以将java byte类型的的数据转换成protobuf的ByteString类型。
    这样就可以将java中的byte类型的数据放入protobuf中定义的bytes类型的对象中了。

      如果想要将protobuf的ByteString类型的数据转换成java中的的byte或者String类型

       	MessageBase messageBase = new MessageBase;
       	// 转换为java中的byte数组
       	byte[] byteArray = messageBase.getData().toByteArray();
      	// 转换为java中的String类型
       	String string = new String(byteArray);
    
    展开全文
  • protobuf中有string 和 bytes两种数据类型, 相对应于python中的 string和 bytes类型。但在C++ 中有::std::string 却没有bytes类型。他们之间怎么转换。 看了一些介绍得到的结论是: (1)在C++中,protobuf的...
  • protobuf提供了多种基础数据格式,包括string/bytes。从字面意义上,我们了解bytes适用于任意的二进制字节序列。然而对C++程序员来讲,std::string既能存储ASCII文本字符串,也能存储任意多个\0的二进制序列。那么...
  • protobuf

    千次阅读 2018-08-08 12:14:11
    protobuf protobuf 优点 编译安装 syntax basic 字段修饰符 字段类型 varint message存储格式 生成代码 基类::google::protobuf::Message 序列化 反序列化 getter、setter - clear_field():重置字段 - ...
  • Protobuf

    2020-08-04 11:00:01
    深入 ProtoBuf-简介 https://www.jianshu.com/p/a24c88c0526a Protobuf: protocol Buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。 可以定义数据的结构,...
  • ProtoBuf

    2020-06-04 20:55:22
    Protocol Buffer(Protobuf): 轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或PRC数据交换格式。 可用于通讯协议,数据存储等领域的语言无关,平台无关,可扩展的序列化结构数据格式。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,285
精华内容 3,714
关键字:

bytesprotobuf