Я знаю, что можно сделать что-то вроде этого:
readlines(FileName) ->
{ok, Device} = file:open(FileName, [read]),
get_all_lines(Device, []).
get_all_lines(Device, Accum) ->
case io:get_line(Device, "") of
eof -> file:close(Device), Accum;
Line -> get_all_lines(Device, Accum ++ [Line])
end.
: Существует ли один лайнер BIF, который может сделать это также?
file:read_file/1 - это то, что вы ищете. Просто для обучения, Accum ++ [Line]
- плохая практика. Проблема в том, что левый аргумент ++
копируется, а правый используется как есть. В вашем коде вы будете копировать все большую и большую часть в каждой итерации. Решением является lists:reverse(Line,Accum)
и затем возврат lists:reverse(Accum)
в ветке eof
(Или [Line|Accum]
и lists: append(lists:reverse(Accum))
в eof
или используйте бинарники с лучшей операцией append или ...). ..). Другой способ - не использовать хвостовую рекурсивную функцию, что не так плохо, как кажется на первый взгляд, согласно Миф: Хвостовые рекурсивные функции намного быстрее рекурсивных.
Итак, ваша функция readlines/1
должна выглядеть так
readlines(FileName) ->
{ok, Device} = file:open(FileName, [read]),
try get_all_lines(Device)
after file:close(Device)
end.
get_all_lines(Device) ->
case io:get_line(Device, "") of
eof -> [];
Line -> Line ++ get_all_lines(Device)
end.