Бинарник — тип данных, а именно битстрока, длина которой делится на 8. Предназначен для хранения и передачи сырых, упакованных данных. То же: binary.
Бинарник предназначен для хранения и передачи (например, через сокеты) хорошо упакованных данных — так, чтобы они занимали как можно меньше места. Эрланг хорошо оптимизирует работу с бинарниками.
Там, где возможно, бинарники следует использовать для хранения неструктурированных данных, например больших строк или содержание какого-либо файла. В Эрланге эффективным является чтение файла сначала в бинарник — с последующим его разбором. И наоборот, при записи данных в файл их следует сначала превратить в бинарник, а бинарник уже и записать в файл.
Бинарник рассматривается как подмножество битстроки — в которой количество битов делится на 8. На практике битстрокой называют те случаи, когда она содержит количество битов, которое не делится на 8.
Литерал бинарника выглядит как последовательность целых чисел (0..255), заключённая в двойные угловые скобки:
1> <<1,10,100,200>>.
<<1,10,100,200>>
Как известно, в Эрланге строк как самостоятельного типа данных нет. Строковые литералы появляются в Системе просто как последовательность соответствующих чисел (согласно кодам).
2> <<1,"Yesterday.",3>>.
<<1,89,101,115,116,101,114,100,97,121,46,3>>
Если угодно, можно использовать числа больше или меньше диапазона 0..255. В Систему тогда попадут числа — целочисленный остаток от деления на 256.
3> <<256,257,258>>.
<<0,1,2>>
4> <<-255,-2,-3>>.
<<1,254,253>>
Можно, конечно, использовать и кириллические буквы. Их коды так же превратятся в числа в диапазоне 0..255.
5> "Ну, погоди!".
[1053,1091,44,32,1087,1086,1075,1086,1076,1080,33]
6> <<"Ну, погоди!">>.
<<29,67,44,32,63,62,51,62,52,56,33>>
Когда с помощью знака равно привязываем бинарник к переменной, надо не забыть ставить пробелы вокруг =
. Иначе будет ошибка, вызванная тем, что =<
воспринимается как “равно или меньше”.
1> B1 = <<1>>.
<<1>>
2> B2 =<<1>>.
* 2:6: syntax error before: '<'
Бинарники можно обрабатывать с помощью специальных функций или же с помощью бит-синтаксиса.
list_to_binary(L) -> B берёт иолист L и превращает его в бинарник.
1> L="hello".
"hello"
2> list_to_binary(L).
<<"hello">>
Иолист это не всякий список, а лишь тот, который состоит из элементов — чисел 0..255, бинарников, других иолистов. Если бы мы вместо “hello” написали “здравствуй”, то получили бы ошибку, потому что коды кириллического юникода заметно больше 255.
Иолист может быть весьма “мохнатым”, но list_to_binary уплощает его, превращая в простую последовательность целых чисел 0..255.
1> L1 = "hello".
"hello"
2> L2 = [L1] ++ "you".
["hello",121,111,117]
3> L3 = [L2] ++ "and you".
[["hello",121,111,117],97,110,100,32,121,111,117]
4> list_to_binary(L3).
<<"helloyouand you">>
Как уже говорилось, иолист может включать в себя бинарник. Он тоже займёт своё место в большом бинарнике.
L4 = [L3] ++ <<"and binarnik">>.
[[["hello",121,111,117],97,110,100,32,121,111,117]|<<"and binarnik">>]
7> list_to_binary(L4).
<<"helloyouand youand binarnik">>
split_binary(Bin, Pos) -> {Bin1, Bin2} берёт бинарник Bin и по позиции Pos режет его на две части. Возвращает кортеж, состоящий из этих двух бинарников.
1> B = <<1,2,3,4,5,6,7>>.
<<1,2,3,4,5,6,7>>
2> split_binary(B,3).
{<<1,2,3>>,<<4,5,6,7>>}
term_to_binary(Term) -> Bin и binary_to_term(Bin) -> Term позволяют любой терм (например, атом или фунтерм) превратить в бинарник. Бинарник можно передать по сети, можно сохранить в файл, а потом прочитать его, извлечь бинарник, а из бинарника вытащить тот самый терм. Это отличная возможность, реализуется она очень просто.
Поскольку, например, фунтерм это тоже терм, его можно превратить в бинарник, передать через сеть на другой конец света, там извлечь и запустить — на тамошней Эрланг-системе.
1> F = fun(X) -> X*X end.
#Fun<erl_eval.42.105768164>
2> B = term_to_binary(F).
<<131,112,0,0,3,89,1,201,188,156,143,16,126,173,32,90,79,
205,206,160,193,177,248,0,0,0,42,0,0,...>>
3> F2 = binary_to_term(B).
#Fun<erl_eval.42.105768164>
4> F2(11).
121
byte_size(Bin) -> Size просто возвращает количество байтов в бинарнике.
1> byte_size(<<"привет">>).
6
Каждая буква из слова “привет” занимает, конечно, два байта. Однако сначала, как мы уже выяснили, код каждой буквы превращается в 0..255, поэтому данный бинарник и имеет размер 6 байтов.
Допустим, у нас есть бинарники <<1,2,3>> и <<4,5>>. Как получить бинарник <<1,2,3,4,5>> ? Для этого можно воспользоваться следующим способом:
1> B1 = <<1,2,3>>.
<<1,2,3>>
2> B2 = <<4,5>>.
<<4,5>>
3> <<B1/binary, B2/binary>>.
<<1,2,3,4,5>>
Для работы с бинарниками часто удобно использовать механизм регулярных выражений (модуль re). Например, с помощью регулярных выражений можно искать в бинарнике:
1> re:run(<<"To be, or not to be, that is the question.">>, "be").
{match,[{3,2}]}
Когда мы работаем с re:replace/4, то приходится задействовать бинарники, когда для замены используем фунтерм. Этот фунтерм должен принимать два аргумента: бинарник и список бинарников.
В опциях часто приходится ставить {return, list}
, чтобы в результате получить строку, а не список из нескольких бинарников.
at(Subject, Pos) -> byte()
Возвращает байт (как целое число) из бинарника Subject по адресу Pos.
bin_to_list(Subject) -> [byte()]
bin_to_list(Subject, PosLen) -> [byte()]
bin_to_list(Subject, Pos, Len) -> [byte()]
Превращают бинарник в последовательность байтов. В зависимости от арности функции меняется и её работа (принимаемые аргументы).
compile_pattern(Pattern) -> cp()
Компилирует паттерн, который потом можно использовать в функциях match/3, matches/3, split/3, и replace/4.
copy(Subject) -> binary()
copy(Subject, N) -> binary()
Из бинарника Subject создаётся новый, в котором исходный бинарник будет повторяться 1 или N раз.
decode_hex(Bin) -> Bin2
Декодирует бинарник в 16-ричной кодировке.
decode_unsigned(Subject) -> Unsigned
decode_unsigned(Subject, Endianness) -> Unsigned
Превращают бинарник в одно большое беззнаковое число.
encode_hex(Bin) -> Bin2
encode_hex(Bin, Case) -> Bin2
Превращает бинарник в 16-ричный формат, например <<"C8FAF0">>
.
encode_unsigned(Unsigned) -> binary()
encode_unsigned(Unsigned, Endianness) -> binary()
Превращает положительное число в бинарник.
first(Subject) -> byte()
Возвращает первый байт.
last(Subject) -> byte()
Возвращает последний байт.
list_to_bin(ByteList) -> binary()
Последовательность байтов превращается в бинарник.
longest_common_prefix(Binaries) -> integer() >= 0
Сравнивает два бинарника и возвращает длину общего префикса.
longest_common_suffix(Binaries) -> integer() >= 0
Сравнивает два бинарника и возвращает длину общего суффикса.
match(Subject, Pattern) -> Found | nomatch
match(Subject, Pattern, Options) -> Found | nomatch
Ищет паттерн в бинарнике и возвращает найденную позицию и длину вхождения.
matches(Subject, Pattern) -> Found
matches(Subject, Pattern, Options) -> Found
Как match, но возвращает несколько результатов.
part(Subject, PosLen) -> binary()
part(Subject, Pos, Len) -> binary()
Извлекает часть бинарника.
referenced_byte_size(Binary) -> integer() >= 0
Если данный бинарник ссылается на больший бинарник, бывает полезно знать размер того бинарника.
replace(Subject, Pattern, Replacement) -> Result
replace(Subject, Pattern, Replacement, Options) -> Result
Создаёт новый бинарник путём изменения части старого.
split(Subject, Pattern) -> Parts
split(Subject, Pattern, Options) -> Parts
Режет бинарник на какое-то количество других бинарников.
Функции модуля binary.
© Алексей Карманов, 2024.