Как прочитать содержимое файла в Erlang?
Я знаю, что вы можете сделать что-то вроде этого:
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, который может сделать это тоже?
2 ответа
file:read_file/1 - это то, что вы ищете. Просто для учебной цели, Accum ++ [Line]
это плохая практика. Проблема в том, что левый аргумент ++
копируется и право используется как есть. В своем коде вы будете копировать все большую и большую часть в каждой итерации. Решение lists:reverse(Line,Accum)
и чем вернуть lists:reverse(Accum)
в вашем eof
филиал (или [Line|Accum]
а также lists:append(lists:reverse(Accum))
на eof
или используйте бинарный файл, который лучше добавляет операцию или...). Другой способ - не использовать хвостовую рекурсивную функцию, которая не так плоха, как кажется в первый раз, согласно Мифу: хвостовые рекурсивные функции НАМНОГО быстрее, чем рекурсивные функции.
Так что ваши 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.
Вы могли бы использовать file:read_file/1
а также binary:split/3
сделать эту работу в два этапа:
readlines(FileName) ->
{ok, Data} = file:read_file(FileName),
binary:split(Data, [<<"\n">>], [global]).