【问题标题】:File IO and list processing文件 IO 和列表处理
【发布时间】:2013-01-06 04:14:34
【问题描述】:

我问了一个类似的问题,不知道有什么不清楚的地方,但我会再试一次。我有一个文件。文件名是 file.txt,我将 file.txt 读入一个列表。现在我可以将它打印到控制台,它会显示:

blah
blah
blah
blah

没关系。完美:) 现在我将如何将其转发到新文件?以便新文件包含:

blah
blah
blah
blah

不多也不少。这是我用来将文件读入列表的代码: {ok, Device} = file:open("file.txt", [read]), Li = readdata(Device, []).

readdata(Device, Accum) ->
case io:get_line(Device, "") of
    eof  -> file:close(Device), Accum;
    Line -> readdata(Device, Accum ++ [Line])
end.

同样,新文件显示的内容与我读取的文件显示的内容完全相同,没有多余的字符,不是全部在 1 行..等等.. 一样:)

【问题讨论】:

    标签: erlang


    【解决方案1】:

    嗯,简单的方法是:

    ok = file:write_file("output.txt", Li).
    

    正如您在 http://www.erlang.org/doc/man/file.html 中看到的那样,有很多有用的函数,例如 file:read_file/1,它们可以缩短您的程序,同时使其更快一点。

    您看,将读取数据与累加器组合的方式并不完美,因为它需要复制 Accum 值,因此您的 readdata/2 函数的复杂度为 N^2。附加到列表的头部是最好的方法,但当然你必须将行存储为 Acc 的值并在最后反转它。

    那么文件的长度呢?如果它很大并且不适合内存,那么即使正确使用累加器也会遇到问题。在这种情况下,标准方法是打开这两个文件,读取一些数据块并立即将其写入输出。

    copy_file() ->
        {ok, In} = file:open("input", [read]),
        {ok, Out} = file:open("output", [write]),
        copy_file(In, Out),
        file:close(In),
        file:close(Out).
    
    copy_file(In, Out) ->
        case file:read(In, 1024 * 64) of
            {ok, Data} ->
                ok = file:write(Out, Data),
                copy_file(In, Out);
            _ ->
                ok
        end.
    

    代码我没试过,可能编译不出来,我只是想展示一下基本思路。

    【讨论】:

    • 文件非常小,在其他语言中它就像:data[] = file.read("file.txt")open = file.open("new.txt")foreach (line in data)file.write(open, line)end`我实际上不想“复制”一个文件,那只是我用来解释我想将数据列表写入一个新文件的定义,就像它在另一个文件中的显示方式一样。我可能希望修改列表并将其写回同一个文件。所以复制只是我使用的一个术语。
    • Erlang 的列表模块确实有一个用于处理列表副作用的 foreach 函数。你可以看看那个。我将尝试将答案与一些代码示例放在一起。
    • 我使用了 foreach,由于某种原因,输出似乎都在文件的 1 行,我尝试了 foreach 和 map,结果相同。
    • 我想我找到了问题,由于某种原因 ~n 无法正常工作,我在 Windows 上换行符是 \r\n 但出于某种原因,我认为 erlang 给了我一个 unix \n ..我怎样才能改变这个?
    • file:read_line/1 的文档中有一句话:“返回的行包括 LF,但不包括紧跟 LF 的任何 CR。”您要么必须使用另一个函数从文件中读取行,要么需要删除最后一个字符并附加窗口的行尾符号。
    【解决方案2】:

    所以这就是我想出的。我稍微修改了您的 readdata/2 以优化附加并删除换行符。 write/2 函数使用 lists:foreach/2 和 io:fwrite/3 写入文件。

    -module(rwlist).
    -export([read/1,write/2]).
    
    read(FileName) ->
       case file:open(FileName, [read]) of
          {ok, Device} ->
             readdata(Device, [])
       end.
    
    readdata(Device, Accum) ->
       case io:get_line(Device, "") of
           eof  -> file:close(Device), lists:reverse(Accum);
           Line -> readdata(Device, [(Line--"\n")|Accum])
       end.
    
    write(FileName, List) ->
       case file:open(FileName, [write]) of
          {ok, Device} ->
             lists:foreach(fun(Line) -> writeline(Device, Line) end, List),
             file:close(Device)
       end.
    
    writeline(Device, Line) -> writeline(Device, Line, os:type()).
    
    writeline(Device, Line, {win32,_}) -> io:fwrite(Device, "~s\r\n", [Line]);
    writeline(Device, Line, _) -> io:fwrite(Device, "~s\n", [Line]).
    

    这是测试...

    57> List=rwlist:read("list").  
    ["item 1","item 2","item 3","item 4"]
    58> rwlist:write("list2", List).
    ok
    59> List2=rwlist:read("list2"). 
    ["item 1","item 2","item 3","item 4"]
    

    当然,如果您只是复制文件,Dmitry 的回答会更好。

    【讨论】:

    • 我修改了示例代码以添加特定于操作系统的 writeline/2 函数,因为 Erlang 格式化程序不适合我们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多