我使用 protobuf-java-util:3.0.0-beta-2。
我创建了一个文件,其中包含许多用Message#writeDelimitedTo()
. 代码是这样的:
Iterable<SomeMessage> messages = getHugeDataSet();
OutputStream os = new FileOutputStream("a_lot_of_messages.protobuf");
for (SomeMessage msg : messages) msg.writeDelimitedTo(os);
我用Builder#mergeDelimitedFrom()
. 像这样的东西:
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
这样,我可以毫无问题地读取绝大多数文件,但有时会遇到如下异常:
com.google.protobuf.InvalidProtocolBufferException: Protocol message had invalid UTF-8. ...
编写这些文件的代码在有时会断电的移动设备上运行。在这种情况下,我的应用程序会一直写入同一个文件,并且出现异常的机会很高。因此,显然我的代码在这种情况下会创建一些格式错误的文件。我的代码可以读取文件的某些部分,但由于错误,它无法读取格式错误的块之后的部分。
现在我需要在格式错误的块之后拯救和读取数据,但我找不到任何方法来做到这一点。所以,我想知道以下几点:
- 有什么办法可以在格式错误的块之后拯救和读取上面代码编写的部分?
- 如果没有办法做到这一点,我该如何改进我的代码,以便我的应用程序能够应对这些问题?有没有可以容忍电源故障的最佳实践?
完整的异常堆栈跟踪是这样的:
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]