Как прочитать содержимое файла в 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]).
Другие вопросы по тегам