yazz.com
yazz.com

Reputation: 58816

How to read the contents of a file In Erlang?

I know you can do something like this:

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.

Is there a one liner BIF that can do this too?

Upvotes: 16

Views: 25879

Answers (2)

pazustep
pazustep

Reputation: 441

You could leverage file:read_file/1 and binary:split/3 to do this work in two steps:

readlines(FileName) ->
    {ok, Data} = file:read_file(FileName),
    binary:split(Data, [<<"\n">>], [global]).

Upvotes: 11

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26131

file:read_file/1 is what you are looking for. Just for teaching purpose, Accum ++ [Line] is bad practice. Problem is that left argument of ++ is copied and right is used as is. In your code you will copy bigger and bigger part in each iteration. Solution is lists:reverse(Line,Accum) and than return lists:reverse(Accum) in your eof branch (Or [Line|Accum] and lists:append(lists:reverse(Accum)) at the eof or use binary which have better append operation or ...). Another way is not using tail recursive function which is not so bad as seems at first time according to Myth: Tail-recursive functions are MUCH faster than recursive functions.

So your readlines/1 function should look like

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.

Upvotes: 34

Related Questions