将BigDecimal/BigInteger序列化为ProtocolBuffers的最佳方法是什么?

Ric*_*ich 24 java protocol-buffers

我开始将自定义序列化机制迁移到Protocol Buffers.将特别定期使用的一种数据类型是BigDecimal.

有没有人知道在Protocol Buffers中序列化这个的好方法?我们当前的序列化例程BigDecimal.toPlainString()用于序列化和new BigDecimal(String)反序列化 - 我假设有更好的方法.

我的猜测是将a定义BigDecimal为:

message BDecimal {
    required int32 scale = 1;
    required BInteger int_val = 2;
}
Run Code Online (Sandbox Code Playgroud)

但我不太清楚如何定义BigInteger- 也许使用它的toByteArray()方法?

not*_*oop 17

是.您应该将BigInteger定义为BigInteger.toByteArray().

我的猜测是BigDecimal会:


message BDecimal {
  required int32 scale = 1;
  required BInteger int_val = 2;
}
Run Code Online (Sandbox Code Playgroud)

而BigInteger可能被定义为


message BInteger {
  required bytes value = 1;
}
Run Code Online (Sandbox Code Playgroud)

处理BigInteger的代码是:


  BInteger write(BigInteger val) {
    BInteger.Builder builder = BInteger.newBuilder();
    ByteString bytes = ByteString.copyFrom(val.toByteArray());
    builder.setValue(bytes);
    return builder.build();
  }

  BigInteger read(BInteger message) {
    ByteString bytes = message.getValue();
    return new BigInteger(bytes.toByteArray());
  }
Run Code Online (Sandbox Code Playgroud)

  • 你如何将BigDecimal转换为BigInteger并扩展?然后回来 ? (3认同)
  • 我一开始担心这种使用“toByteArray”的方法可能不可移植(无法从 Java 以外的语言进行有意义的反序列化——这通常是首先使用 protobuf 的主要原因之一)。然而, [`BigInteger.toByteArray`](http://docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html#toByteArray()) 的规范非常具体,并且可以轻松使用其他语言(例如 [.net BigInteger](http://msdn.microsoft.com/en-us/library/dd268207(v=vs.110).aspx),尽管您必须小心,因为字节序似乎是不同的)。 (2认同)

Die*_*ida 12

我最近有与OP相同的需求,并使用了与@notnoop提出的类似的解决方案。看到 @stikkos 的评论后将其发布在这里:

\n
\n

如何将 BigDecimal 转换为 BigInteger 并进行缩放?然后回来 ?

\n
\n

根据BigDecimal课程文档

\n
\n

的值为BigDecimal( unscaledVal\xc3\x97 10-scale ),根据精度和舍入模式设置进行舍入。

\n
\n

因此,java.math.BigDecimal可以考虑三个属性来序列化 a:

\n\n
\n

现在,代码。

\n
    \n
  1. Protobuf v3 消息定义:

    \n
    syntax = "proto3";\n\nmessage DecimalValue {\n  uint32 scale = 1;\n  uint32 precision = 2;\n  bytes value = 3;\n}\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. 如何将 a 序列java.math.BigDecimal化为 Protobuf 消息:

    \n
    syntax = "proto3";\n\nmessage DecimalValue {\n  uint32 scale = 1;\n  uint32 precision = 2;\n  bytes value = 3;\n}\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. 如何将 Protobuf 消息反序列化回java.math.BigDecimal

    \n
    import com.google.protobuf.ByteString;\nimport DecimalValue;\n\njava.math.BigDecimal bigDecimal = new java.math.BigDecimal("1234.56789");\nDecimalValue serialized = DecimalValue.newBuilder()\n        .setScale(bigDecimal.scale())\n        .setPrecision(bigDecimal.precision())\n        .setValue(ByteString.copyFrom(bigDecimal.unscaledValue().toByteArray()))\n        .build();\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
  7. 我们可以检查获得的产量java.math.BigDecimal是否与原始值相同,如下所示:

    \n
    java.math.MathContext mc = new java.math.MathContext(serialized.getPrecision());\njava.math.BigDecimal deserialized = new java.math.BigDecimal(\n        new java.math.BigInteger(serialized.getValue().toByteArray()),\n        serialized.getScale(),\n        mc);\n
    Run Code Online (Sandbox Code Playgroud)\n
  8. \n
\n
\n

java.math.BigDecimal注意:OP 假设有比使用普通更好的方法来序列化 a String。在存储方面,这个解决方案更好。

\n

例如,要序列化 ​​\xcf\x80 的前 100 位小数:

\n
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679\n
Run Code Online (Sandbox Code Playgroud)\n
assert bigDecimal.equals(deserialized);\n
Run Code Online (Sandbox Code Playgroud)\n

这产生:

\n
DecimalValue: 48\nString: 104\n
Run Code Online (Sandbox Code Playgroud)\n