MessagePack って何?
最近よく聞くMessagePackとは何かを調べたのでメモ。
MessagePackとは
バイナリでデータを保存するフォーマットです。
JSONと比べると、保存した状態の可読性を犠牲にする代わりに、
より早くて小さいフォーマットになっています。
また、汎用的なフォーマットのため、
いろんな言語(nodeとかrubyとかcppとか)
で相互にデータを使えます。
他のバイナリシリアライズフォーマットとの差
MessagePackはバッファをうまく使って早かったり、
読み込み途中でもデシリアライズできるとか、
結構いろいろと高速化のための工夫がされています。
(ただし、実装によって若干違いがあるようです)
使い方
rubyならgem install msgpack
で、
MacのC++ならbrew install msgpack
で使えるようになります。
なお、C++はgccに以下のオプションをつける必要があります。
g++ test.cpp -lmsgpack -o test
また、基本型は全てシリアライズ可能で、保存したいクラスのメンバ変数を、
MSGPACK_DEFINEマクロに入れると、
自動でシリアライズ/デシリアライズできるみたいです。
コード
C++
#include <msgpack.hpp>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
struct User {
User(std::string name, int id, std::vector<int> follower)
: name(name)
, id(id)
, follower_id(follower)
{}
// 引数なしのコンストラクタは必須
User()
: id(0)
{}
MSGPACK_DEFINE(name, id, follower_id);
std::string name;
int id;
std::vector<int> follower_id;
string toString(){
string ret = "name: ";
ret += name;
ret += " id: ";
ret += std::to_string(id);
ret += " follower: ";
for(int i=0; i<follower_id.size(); ++i){
ret += std::to_string(follower_id[i]);
ret += " ";
}
return ret;
}
};
int main(void) {
// データを作って書き込む
std::vector<int> follower_1;
follower_1.push_back(1);
follower_1.push_back(2);
std::vector<int> follower_2;
follower_2.push_back(2);
std::vector<User> users;
users.push_back(User("user1", 1, follower_1));
users.push_back(User("user2", 2, follower_2));
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, users);
ofstream myFile ("cpp_data.bin", ios::out | ios::binary);
myFile.write(sbuf.data(), sbuf.size());
myFile.close();
// ファイルからデータを読み込む
char buffer[1000];
ifstream inFile ("ruby_data.bin", ios::in | ios::binary);
inFile.read (buffer, 1000);
inFile.close();
msgpack::unpacked msg;
msgpack::unpack(&msg, buffer, 1000);
msgpack::object obj = msg.get();
std::vector<User> load_users;
obj.convert(&load_users);
for(int i=0; i<load_users.size(); ++i){
cout << load_users[i].toString() << endl;
}
return 0;
}
ruby
require 'msgpack'
# load data and deserialize
users = MessagePack.unpack( File.open("cpp_data.bin") )
p users
# serialize and output data
users[0][0] = "100user"
users[0][1] = 100
users[0][2] = [100, 101]
users[0][0] = "101user"
users[0][1] = 101
users[0][2] = [101]
File.open('ruby_data.bin','w') do |f|
f.print users.to_msgpack
end