【问题标题】:How to read the contents of a file In Erlang?如何在 Erlang 中读取文件的内容?
【发布时间】:2020-04-15 02:13:31
【问题描述】:

我知道你可以这样做:

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 也可以做到这一点?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    file:read_file/1 是您正在寻找的。仅出于教学目的,Accum ++ [Line] 是不好的做法。问题是 ++ 的左参数被复制,而右参数按原样使用。在您的代码中,您将在每次迭代中复制越来越大的部分。解决方案是lists:reverse(Line,Accum),然后在您的eof 分支中返回lists:reverse(Accum)(或eof 中的[Line|Accum]lists:append(lists:reverse(Accum)),或使用具有更好附加操作的二进制文件或...)。另一种方法是不使用尾递归函数,根据Myth: Tail-recursive functions are MUCH faster than recursive functions,这并不像第一次看起来那么糟糕。

    所以你的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 是不是有点危险?我的意思是它正在使用看起来像是阻塞的file_server(包装prim_file的gen_server)。看起来 prim_file 或 file_io_server 可能是更好的解决方案。
    • 我没有遇到或听说过file:read_file 的任何问题。我不明白它应该阻止什么。
    【解决方案2】:

    您可以利用file:read_file/1binary:split/3 分两步完成这项工作:

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

    【讨论】:

    • 你真的想在这里做一个case语句,因为文件不存在。 case file:read_file(FileName) of {ok, Data} -> ... {error, _} -> ... end.
    • @MatthewDaiter 不,让它崩溃。
    猜你喜欢
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 2012-01-29
    • 2011-05-03
    • 2013-02-14
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多