Битовые сдвиги в Erlang
Для перелезших с Сишечки посвящается.
Битовые сдвиги в Erlang
Для перелезших с Сишечки посвящается.
Последнее время я часто сижу по веществами…

…и захотел я 150-метровую базу сдампить в файл. База с данными stackoverflow, один чел уже загнал её во мнезию, хотел свою такую-же только не в убогом исполнении:

Решил я по старинке наговнокодить:
t_write() ->
{ok,IoDevice}=file:open("file.bin",[write,raw,binary]),
file:write(IoDevice,<<"sasay\n">>),
file:write(IoDevice,<<"lalka">>),
ok=file:close(IoDevice).
t_read() ->
{ok,IoDevice}=file:open("file.bin",[read,raw,binary]),
Foreach=fun ReadLine(Fun) ->
case file:read_line(IoDevice) of
eof -> ok=file:close(IoDevice);
{error, _Reason} -> ok=file:close(IoDevice);
{ok, Data} -> Fun(Data), ReadLine(Fun)
end end,
Foreach(fun(Data) -> io:format("Part: ~p~n",[Data]) end).
И результат после сохранения и восстановления базы:
main:t_db_restore().
** exception error: bad argument
in function binary_to_term/1
called as binary_to_term([131,104,13,100,0,9,111,112,101,114,97,116,105,111,110,97,5,100,0,9,117,110,100,101,102,105,110,101|…])
В общем, такие дела, посоны, что вы не должны хотеть писать данные в файл построчно :) Либо файл целиком file:write_file/3, либо чанками file:write/2. Никаких сепараторов. Логика парсинга должна быть вынесена из уровня стандартной библиотеки на уровень приложения.
Так как записи таблицы мы кодируем в рассово-верный BERT, надо определиться с разделителями. Допустим, ими будет смещение до следующего рекорда.
<<9>> <<131,104,1,100,0,3,120,117,121>>
Смещение должно быть фиксированного размера, и например, могло описать число 4'294'967'295 — кул, уложимся в 32 бита, классика.
Надо было нарезать длину упакованого в BERT рекорда на 4 байта.
Тут я зачем-то вспомнил Си с битовыми сдвигами, и как в нём всё быстро — и уехал в астрал.
Дело в том, что в Эрланге битовый сдвиг влево — арифметический, то есть биты сдвигаясь влево не теряются, ведь тип Integer не ограничен в размере. Поэтому сегодня без битовых сдвигов, бро.
Решение простое:
<<4294967295:32>>. => <<255,255,255,255>>
<<3672:32>>. => <<0,0,14,88>>
Идеально. Обратно тоже работает. ВНЕЗАПНО
<<N:32>> = <<1,0,1,0>>.
N. => 16777472
Теперь надо переписать построчные говнофункции.
t_db_store2() ->
mnesia:transaction(fun()->
{ok,IoDevice}=file:open("table.dat",[write,raw,binary]),
mnesia:foldl(fun(Record,Acc) ->
Bin=term_to_binary(Record),
file:write(IoDevice,<<(size(Bin)):32,Bin/binary>>),
Acc
end,undefined,TABLE_NAME),
ok=file:close(IoDevice) end).
t_db_restore2() ->
{ok,IoDevice}=file:open("table.dat",[read,raw,binary]),
Foreach=fun ReadBlock(Fun) when is_function(Fun) ->
ReadBlock({header,4,Fun});
ReadBlock({Type,Count,Fun}) ->
case file:read(IoDevice,Count) of
eof -> ok=file:close(IoDevice);
{error, _Reason} -> ok=file:close(IoDevice);
{ok, <<BlockSize:32>>} when Type =:= header ->
ReadBlock({data,BlockSize,Fun});
{ok, Data} when Type =:= data ->
Fun(Data),
ReadBlock({header,4,Fun})
end
end,
Foreach(fun(Data) ->
io:format("Part: ~p~n",[binary_to_term(Data)]) end).
Ладно. Раз уж статья про битовые операции, нате вам хотя бы замену erlang:now() который deprecated начиная с R18
integer_to_list(unique_integer() rem 1000000). 메타데이터
- post_id
- ddcc4f857599
- slug
- битовые-сдвиги-в-erlang-ddcc4f857599
- url
- https://medium.com/@m2k/%D0%B1%D0%B8%D1%82%D0%BE%D0%B2%D1%8B%D0%B5-%D1%81%D0%B4%D0%B2%D0%B8%D0%B3%D0%B8-%D0%B2-erlang-ddcc4f857599
- canonical_url
- https://medium.com/@m2k/%D0%B1%D0%B8%D1%82%D0%BE%D0%B2%D1%8B%D0%B5-%D1%81%D0%B4%D0%B2%D0%B8%D0%B3%D0%B8-%D0%B2-erlang-ddcc4f857599
- author_url
- https://medium.com/@m2k
- status
- ok
- fetched_at
- 2026-08-27 01:51:41