仕事でバイナリフォーマットを扱う機会がありそうなので MessagePack の Encode/Decode を Go, Python, Scala で試してみました。
- macOS: 10.12.1
- Go: 1.7
- Python: 2.7.12
- Scala: 2.12.0
データの準備
以下の JSON を msgpack-cli で MessagePack にシリアライズする。
$ go get github.com/jakm/msgpack-cli
$ cat test.json | jq
{
"timestamp": 1478743555,
"user": "bob",
"age": 28
}
$ msgpack-cli encode test.json --out test.bin
$ msgpack-cli decode test.bin --pp
{
"age": 28,
"timestamp": 1478743555,
"user": "bob"
}
サイズ比較と hexdump で 16進数 と ASCII を出力して中身を確認してシリアライズされていることを確認。
$ ls -lh test.*
-rw-r--r-- 1 user staff 30B 12 4 00:35 test.bin
-rw-r--r-- 1 user staff 52B 12 4 00:35 test.json
$ hexdump -C test.json
00000000 7b 22 74 69 6d 65 73 74 61 6d 70 22 3a 20 31 34 |{"timestamp": 14|
00000010 37 38 37 34 33 35 35 35 2c 20 22 75 73 65 72 22 |78743555, "user"|
00000020 3a 20 22 62 6f 62 22 2c 20 22 61 67 65 22 3a 20 |: "bob", "age": |
00000030 32 38 7d 0a |28}.|
00000034
$ hexdump -C test.bin
00000000 83 a9 74 69 6d 65 73 74 61 6d 70 ce 58 23 d6 03 |..timestamp.X#..|
00000010 a4 75 73 65 72 a3 62 6f 62 a3 61 67 65 1c |.user.bob.age.|
0000001e
Go
Go では ugorji/go を使ってみる。
$ go get github.com/ugorji/go/codec
package main
import (
"github.com/ugorji/go/codec"
"io/ioutil"
"log"
)
var (
v interface{} // value to decode/encode into
b []byte
mh codec.MsgpackHandle
)
func DecodeMessagePack(buf []byte) error {
err := codec.NewDecoderBytes(buf, &mh).Decode(&v)
if err != nil {
return err
}
log.Printf("Decoded: %#v", v)
return err
}
func main() {
b, err := ioutil.ReadFile("../data/test.bin")
if err != nil {
log.Println(err)
}
log.Printf("MessagePack: %#v", b)
err = DecodeMessagePack(b)
if err != nil {
log.Println(err)
}
}
$ go run ugori_example.go
2016/12/04 00:39:34 MessagePack: []byte{0x83, 0xa9, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0xce, 0x58, 0x23, 0xd6, 0x3, 0xa4, 0x75, 0x73, 0x65, 0x72, 0xa3, 0x62, 0x6f, 0x62, 0xa3, 0x61, 0x67, 0x65, 0x1c}
2016/12/04 00:39:34 Decoded: map[interface {}]interface {}{"timestamp":0x5823d603, "user":[]uint8{0x62, 0x6f, 0x62}, "age":28}
Python
Python では msgpack-python を使ってみる。
$ pip install msgpack-python
# -*- coding: utf-8 -*-
import msgpack
from io import BytesIO
buf = BytesIO()
with open("../data/test.bin", "rb") as f:
buf.write(f.read())
buf.seek(0)
unpacker = msgpack.Unpacker(buf)
for unpacked in unpacker:
print(unpacked)
$ python msgpack_example.py
{'timestamp': 1478743555, 'age': 28, 'user': 'bob'}
msgpack-python 以外の候補として u-msgpack-python もある。
Scala
Scalaでは msgpack-scala を使ってみる。
build.sbt に以下を追加する。
libraryDependencies += "org.msgpack" %% "msgpack-scala" % "0.6.11"
libraryDependencies += "org.slf4j" % "slf4j-log4j12" % "1.7.10"
Scala(Java)力が足りなくて, test.bin から Decode が上手くできなかったのが悔やまれる。
import org.msgpack.annotation.Message
import org.msgpack.ScalaMessagePack
@Message // Don't forget to add Message annotation.
class Test{
var timestamp : Int = 0
var user : String = ""
var age : Int = 0
}
object MessagePack{
def main(args: Array[String]){
val obj = new Test()
obj.timestamp = 1478743555
obj.user = "bob"
obj.age = 28
val serialized : Array[Byte] = ScalaMessagePack.write(obj)
println(serialized)
val deserialized : Test = ScalaMessagePack.read[Test](serialized)
println(deserialized)
}
}
Scalaでは msgpack4z も良さそう。
[1] Go の msgpack ライブラリ比較
[2] ドワンゴオリジナルのScala研修資料
[3] java.lang.ClassNotFoundException: org.slf4j.LoggerFactory in Intellij, scala project with playframework
[4] Scala入門時に役立つ情報まとめ