首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在用writeDelimitedTo()编写的字节流中恢复格式错误的块后的数据

如何在用writeDelimitedTo()编写的字节流中恢复格式错误的块后的数据
EN

Stack Overflow用户
提问于 2017-11-13 02:09:39
回答 1查看 551关注 0票数 1

我使用protobuf-java-util:3.0.0-beta-2。

我创建了一个包含大量Protobuf消息的文件,这些消息是用Message#writeDelimitedTo()编写的。代码是这样的:

代码语言:javascript
复制
Iterable<SomeMessage> messages = getHugeDataSet();
OutputStream os = new FileOutputStream("a_lot_of_messages.protobuf");
for (SomeMessage msg : messages) msg.writeDelimitedTo(os);

我用Builder#mergeDelimitedFrom()看了那些文件。就像这样:

代码语言:javascript
复制
InputStream is = new FileInputStream("a_lot_of_messages.protobuf");
SomeMessage msg1 = SomeMessage.newBuilder().mergeDelimitedFrom(is).build();
SomeMessage msg2 = SomeMessage.newBuilder().mergeDelimitedFrom(is).build();
... // This is simplified - it's implemented as an Iterator in the real code

通过这种方式,我可以没有任何问题地读取绝大多数文件,但有时会遇到这样的异常:

代码语言:javascript
复制
com.google.protobuf.InvalidProtocolBufferException: Protocol message had invalid UTF-8. ...

编写这些文件的代码运行在有时会停电的移动设备上。在这种情况下,我的应用程序一直在写同一个文件,获得异常的几率很高。因此,显然我的代码在这种情况下会创建一些格式错误的文件。我的代码可以读取文件的某些部分,但由于错误,它无法读取格式错误的块之后的部分。

现在,我需要拯救和读取数据后的畸形块,但我找不到任何方法去做。因此,我想知道以下几点:

  1. 是否有任何方法来拯救和读取部分,这些部分是由上面的代码在错误的块之后编写的?
  2. 如果没有办法做到这一点,我如何改进我的代码,使我的应用程序能够处理这些问题?有什么最好的做法是电力故障容忍吗?

完全异常堆栈跟踪如下所示:

代码语言:javascript
复制
com.google.protobuf.InvalidProtocolBufferException: Protocol message had invalid UTF-8.
    at com.google.protobuf.InvalidProtocolBufferException.invalidUtf8(InvalidProtocolBufferException.java:120) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.CodedInputStream.readStringRequireUtf8(CodedInputStream.java:410) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.example.Model$SomeData.<init>(Model.java:14775) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeData.<init>(Model.java:14717) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeData$1.parsePartialFrom(Model.java:18240) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeData$1.parsePartialFrom(Model.java:18234) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.google.protobuf.CodedInputStream.readMessage(CodedInputStream.java:495) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.example.Model$SomeMessage.<init>(Model.java:27250) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeMessage.<init>(Model.java:27197) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeMessage$1.parsePartialFrom(Model.java:28678) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeMessage$1.parsePartialFrom(Model.java:28672) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeMessage$Builder.mergeFrom(Model.java:27802) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.example.Model$SomeMessage$Builder.mergeFrom(Model.java:27653) ~[my-app-1.0-SNAPSHOT.jar:na]
    at com.google.protobuf.AbstractMessageLite$Builder.mergeFrom(AbstractMessageLite.java:235) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:516) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:290) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.AbstractMessageLite$Builder.mergeDelimitedFrom(AbstractMessageLite.java:305) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.AbstractMessage$Builder.mergeDelimitedFrom(AbstractMessage.java:530) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.AbstractMessageLite$Builder.mergeDelimitedFrom(AbstractMessageLite.java:311) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.google.protobuf.AbstractMessage$Builder.mergeDelimitedFrom(AbstractMessage.java:522) ~[protobuf-java-3.0.0-beta-2.jar:na]
    at com.example.MyUtils.read(MyUtils.java:54) [my-app-1.0-SNAPSHOT.jar:na]
EN

Stack Overflow用户

回答已采纳

发布于 2017-11-15 06:13:16

从原始原型数据中恢复消息边界是很有问题的。这通常适用于数据格式,它越小越压缩,它对传输错误的弹性就越小。

最好的方法是在消息开始时总是出现一些字节序列。例如,如果您碰巧有任何接近常量的字段(如required string software_version = 1; ),则可以在二进制数据中搜索该字段,从而找到下一条消息的起始点。

如果不是这样的话,您可以在编写消息时引入这样的标记。例如,选择64位随机数作为标记。您可以将其单独写入protobuf之外的文件,也可以在消息中有一个索引1的fixed64字段,以使其接近开始。

尽管标记可能随机出现在数据的其他地方,但这不应导致太大的问题,因为您可以跳过不解析的消息。

票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47256157

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档