2015-02-07 1 views
0

Я пытаюсь использовать MessagePack для сериализации целых чисел в Erlang и Java.Предоставляет ли MessagePack полные целые числа?

В Java Я могу заполнить массив, содержащий одно целое число с таким количеством 0, как я желаю, и MessagePack.read() все еще возвращает правильное значение. Но в Erlang msgpack:unpack/1 сбой, если есть дополнительные нули.

0 Например, msgpack:unpack/1<<10>> работает как ожидалось {ok,10}. Но добавление дополнительных нулей и прохождение <<10,0,0>> не удается, возвращая {error,not_just_binary}. Комментарии в API утверждают, что ошибка означает, что термин был декодирован, но остается двоичным.

ответ

0

В то время как я просматривал источник API Erlang, чтобы получить дополнительную информацию, чтобы задать этот вопрос, я заметил еще одну функцию: msgpack:unpack_stream/1, которая возвращает кортеж с первым расшифрованным термином, соединенным с посторонним двоичным кодом, вместо того, чтобы возвращать ошибку. Это ведет себя по строкам read в Java.

Но я все равно хотел бы знать, есть ли лучший способ сделать это, например, использовать тип фиксированной длины.

1

Библиотека msgpack не предназначена для декодирования исходных двоичных файлов, но двоичные файлы, которые ранее были закодированы с помощью msgpack: pack.

Причина в том, что двоичный файл не имеет структуры сам по себе, поэтому вы должны включить в него некоторую информацию, чтобы разрешить декодирование. Это то, что функция, как term_to_binary делает, используя Эрланга внешний формат:

1> B = term_to_binary({12,atom,[$a,$l,$i,$s,$t]}). 
<<131,104,3,97,12,100,0,4,97,116,111,109,107,0,5,97,108, 
    105,115,116>> 
2> binary_to_term(B). 
{12,atom,"alist"} 

Библиотека msgpack позволяет использовать другой метод кодирования.

Приходит к вашей проблеме. Разница между распаковкой и unpack_stream заключается в том, что первые ожидают один единственный закодированный термин в двоичном выражении, а второй предположим, что конечный двоичный код содержит другие закодированные термины.

, когда вы вызываете msgpack:unpack(<<10>>), он попадает в случай, когда первый элемент меньше 128: в этом случае кодированное значение является самим значением. Если бы вы пытались что-то большее, чем 127, вы получили ошибку:

4> msgpack:unpack(<<10>>). 
{ok,10} 
5> msgpack:unpack(<<200>>). 
{error,incomplete} 
6> 

при вызове msgpack:unpack_stream(<<10>>), это делает точно то же самое, так что первый элемент декодируется, в результате 10, а остальная часть двоичный обеспечиваются сюда дальнейшее декодирование:

8> {A,Rest} = msgpack:unpack_stream(<<10,0>>). 
{10,<<0>>} 
9> msgpack:unpack_stream(Rest).    
{0,<<>>} 
10> msgpack:unpack_stream(<<200,0>>).    
{error,incomplete} 
11> msgpack:unpack_stream(<<200,0,0>>). 
{error,incomplete} 
12> msgpack:unpack_stream(<<200,0,0,0>>). 
{error,{badarg,{bad_ext,200}}} 
13> 

Правильный способ использовать библиотеку, чтобы закодировать первые ваше сообщение:

13> Msg = msgpack:pack(<<10,0,0>>). 
<<163,10,0,0>> 
14> msgpack:unpack(Msg).     
{ok,<<10,0,0>>} 

или в первом примере:

24> Msg1 = msgpack:pack(msgpack:term_to_binary({12,atom,[$a,$l,$i,$s,$t]})).  
<<183,199,20,131,131,104,3,97,12,100,0,4,97,116,111,109, 
    107,0,5,97,108,105,115,116>> 
25> {ok,Rep1} = msgpack:unpack(Msg1).          
{ok,<<199,20,131,131,104,3,97,12,100,0,4,97,116,111,109, 
     107,0,5,97,108,105,115,116>>} 
26> msgpack:binary_to_term(Rep1). 
{12,atom,"alist"} 
27> 

[править]

здесь является предложение добавить отступы и распаковщик, что обнаружить его. Он использует unpack_stream, потому что невозможно изменить способ кодирования целого.

Packer = fun(X, Opt) -> {ok, {12,<<>>}} end, 
Unpacker = fun(12, _) -> {ok, padding} end, 
Opt = [{ext,{Packer,Unpacker}}], 
Pad = fun(B) -> Size = 10 - size(B), SB = Size*8,<<B/binary,16#C7,Size,12,0:SB>> end, 
R = msgpack:pack(256897), 
Var = Pad(R), 
{I,Rest} = msgpack:unpack_stream(Var,Opt), 
{padding,<<>>} = msgpack:unpack_stream(Rest,Opt). 
+0

Большая часть вашего ответа основана на убеждении, что я пытался декодировать случайные двоичные файлы ...которого я не был. Я полностью понимаю, что 0-127 - это единственные значения, которые кодируют 1 байт в кодировке MessagePack. Я выбрал 10 как удобное значение для вопроса, потому что у него нет значимой текстовой кодировки для erlang для печати в виде битовой строки. –

+0

Мой вопрос в том, есть ли способ обозначить целое число с фиксированной шириной (или дополнением). Использование 'unpack_stream' работает, как я упоминал ниже, но это не то же самое, что фиксированный термин ширины, он игнорирует дополнение, которое я добавляю вручную. Я бы предпочел не добавлять дополнения, которые могут мешать определенным значениям. –

+0

Ну, если вы добавите некоторое конечное значение в кодированное сообщение, вы просто испортите его. Как я уже сказал, паровая версия здесь предназначена для обработки потока термина, декодирования первого и предоставления остальных для дальнейшего декодирования; в его контексте добавленный 0 можно интерпретировать как дополнительные члены, равные 0. Бинарники работают на уровне байтов, нет необходимости добавлять байты заполнения. Замечание: целые числа не имеют фиксированной длины в erlang, малые целые числа кодируются по 28 бит (32 бита) или 60 бит (64 бита) и беззвучно используют большое числозначение (слова 3..N), когда они становятся больше , – Pascal