Serialization 如何以人类可读的方式记录嵌套对象中的Protobuf字符串?

Serialization 如何以人类可读的方式记录嵌套对象中的Protobuf字符串?,serialization,protocol-buffers,protobuf-java,Serialization,Protocol Buffers,Protobuf Java,给定一个proto文件: syntax = "proto3"; package hello; message TopGreeting { NestedGreeting greeting = 1; } message NestedGreeting { Greeting greeting = 1; } message Greeting { string message = 1; } 以及守则: public class Main { pub

给定一个proto文件:

syntax = "proto3";
package hello;

message TopGreeting {
    NestedGreeting greeting = 1;
}

message NestedGreeting {
    Greeting greeting = 1;
}

message Greeting {
    string message = 1;
}
以及守则:

public class Main {
    public static void main(String[] args) {
        System.out.printf("From top: %s%n", newGreeting("오늘은 무슨 요일입니까?"));
        System.out.printf("Directly: %s%n", "오늘은 무슨 요일입니까?");
        System.out.printf("ByteString: %s", newGreeting("오늘은 무슨 요일입니까?").toByteString().toStringUtf8());
    }

    private static Hello.TopGreeting newGreeting(String message) {
        Hello.Greeting greeting = Hello.Greeting.newBuilder()
                .setMessage(message)
                .build();
        Hello.NestedGreeting nestedGreeting = Hello.NestedGreeting.newBuilder()
                .setGreeting(greeting)
                .build();
        return Hello.TopGreeting.newBuilder()
                .setGreeting(nestedGreeting)
                .build();
    }
}
输出

From top: greeting {
  greeting {
    message: "\354\230\244\353\212\230\354\235\200 \353\254\264\354\212\250 \354\232\224\354\235\274\354\236\205\353\213\210\352\271\214?"
  }
}

Directly: 오늘은 무슨 요일입니까?

ByteString: 
%
#
!오늘은 무슨 요일입니까?

如何以可读的方式打印消息?如您所见,通过testring转换为
可以打印UTF-8字符,但也可以打印一些其他垃圾
%
#
protobuf二进制格式不是人类可读的,您不应该尝试这样做。如果需要,可以使用JSON变体,但坦率地说,最好记录解释后的数据,而不是有效负载。

回答我自己的问题,我通过挖掘Protobuf源代码解决了这个问题

System.out.println(TextFormat.printer().escapingNonAscii(false).printToString(greeting))
输出:

greeting {
  greeting {
    message: "오늘은 무슨 요일입니까?"
  }
}
toString
使用相同的机制,但带有
转义NonaScii(true)
(省略时为默认值)


另请参阅如何将八进制序列转换为UTF-8字符,以防您无法访问源代码,只能使用日志。

我不同意。几乎总是,一个响应的一部分并不独立,它的解释取决于其他部分。查看整个消息对于调试非常重要,并且可以使用ASCII字符集正常工作。让我感到奇怪的是,谷歌刻意掩盖了印刷的内容,@AbhijitSarkar,你误解了GPB的目的。谷歌把它设计成一个二进制串行器,专门用来节省存储空间。文本序列化可以笨拙地理解为纯文本,它占用了更多的空间,通过网络连接发送需要更长的时间。@bazza我想你误解了我的意思。没有人会阻止谷歌在网络上做最好的事情;我说的是为了调试而打印消息,而不是在任何地方传输它们。调试仍然是由程序员完成的,他们通常是人类。@AbhijitSarkar啊,我明白了,对不起。等一下,我去挖点东西。我的第一直觉是GBP有特定的表示字符串的方法,如果使用不同的字符编码,它可能会丢失。@Abhijit很长时间都是内容,而不是序列化负载,这就是您现在正在做的。序列化负载不可读取。源代码或那些字符串文字是否可能是UTF16或UTF8以外的格式?引起我注意的是,它有像“\354\230\244”这样的输出,但是空格是完整的。其中一些数字大于255,因此我想知道它是否试图输出16位值。如果它将UTF8作为字节值转储,我希望它们是Hello agan,我在这个答案中发现Java字符串是UTF16,这可能与字符串在调试输出中的显示方式有关。如果GPB类期望其缓冲区包含UTF8编码的文本,但实际上它包含UTF16编码的文本,那么它将奇怪地打印出来;这两种编码不兼容。我想知道,在初始化
newgreeting
?@bazza之前,您是否可以使用类似于此的答案将字符串文字转换为UTF8?请参阅我的答案。几乎总是,真相在源代码中。很好的发现:-)我应该发现八进制。。。我在这里找到了ref,默认的tostring()显然是垃圾。对象中的字符串编码应该是UTF8,因此人们会认为它至少会尝试不将其打印为7位ascii。我猜想它依赖于标准的UTF8理解——你的理解很明显——但它并不是万能的。我想知道Windows和Linux上是否有不同的行为。