Reading Lines from a File
From Erlang Community
Contents |
[edit] Problem
You wish to read lines of text from an Io Device.
[edit] Solution
Erlang offers the get_line function for reading lines of text from an IoDevice. The following are some useful procedures which use get_line to make it easy to process an entire file, one line at a time. This code was adapted from the comp.lang.scheme thread, How to read lines from a text file.
The following is a straightforward implementation which allows the programmer to provide a procedure which will be called with each new line read from a file.
for_each_line_in_file(Name, Proc, Mode, Accum0) ->
{ok, Device} = file:open(Name, Mode),
for_each_line(Device, Proc, Accum0).
for_each_line(Device, Proc, Accum) ->
case io:get_line(Device, "") of
eof -> file:close(Device), Accum;
Line -> NewAccum = Proc(Line, Accum),
for_each_line(Device, Proc, NewAccum)
end.
|
For documentation of the optional mode parameters, see the Erlang file module documentation.
[edit] Example
The following will display the source code from the file complex.erl, with line numbers.
1> A = for_each_line_in_file("complex.erl",
1> fun(X, Count) -> io:fwrite("~10B: ~s", [Count, X]),
1> Count + 1 end, [read], 0).
|
Yielding:
0: -module(complex).
1: -export([make/2, is_complex/1, add/2, sub/2, mult/2, divide/2,
2: get_real/1, get_imaginary/1]).
3:
4: -record( complex, {real, imaginary}).
5:
6: is_complex(X) when record(X, complex) -> true;
7: is_complex(_) -> false.
8:
[ ... ]
40: ((A#complex.imaginary * B#complex.real)
41: - (A#complex.real * B#complex.imaginary)) / Divisor).
42:
43: get_real(X) -> X#complex.real.
44:
45: get_imaginary(X) -> X#complex.imaginary.
ok
|
[edit] Discussion
Notice that line numbering is achieved without needing to mutate a variable (an important skill in a single-assignment language, like Erlang!). The user-supplied procedure simply accepts a line-num argument, and when it's done, returns the next value for that argument. The initial line number is supplied as the last argument to the for_each_line helper function, and the user-supplied function is expected to accept an accumulator (or in this case, a count) variable that holds the current state.
This general pattern is called a fold, which is a functional generalization of iteration. There are many such examples in the Erlang distribution, such as the canonical lists:foldl function for folding over lists.

Digg It
Del.icio.us
Reddit
Facebook
Stumble Upon
Technorati

