2017-02-20 46 views
1

我在为自己的研究教授自己的Elixir,通常我的研究需要打开几十或者几百个文本文件,结合这些文件中的数据以及操纵数据。我想知道如何打开目录中的所有文件并访问所有这些文件中的数据。我想避免使用for循环,因为循环遍历100个文件会非常缓慢。我认为Stream模块非常适合我的目的,但我不知道如何使用它。在Elixir中打开并收集多个文件中的数据

下面我有一些测试代码。它所要做的就是打开一堆包含随机数的文件,将文件中的数字字符串转换为整数,然后对它们进行排序。除了开放文件部分,一切都可以工作你可以看到我试图使用Path模块,并且它可以成功找到所有文件,但是我不知道如何以可用的方式将它传递给sort_num函数。谢谢大家的帮助!

defmodule OpenFiles do 

    def file_open do 
    Path.wildcard("numfiles/*.txt") 
    end 

    def sort_num do 
    file_open 
    |> File.stream! 
    |> Stream.map(&String.strip/1) 
    |> Stream.map(&String.to_integer/1) 
    |> Enum.sort 
    end 
end 

IO.inspect OpenFiles.sort_num 

回答

2

File.stream!/3函数一次只能对一个文件起作用。如果您使用通配符并一次收集多个文件,则它不会按您期望的方式工作。

如果你看看Path.wildcard/2的回报,你会得到一个匹配的所有文件的列表。沿

["foo.txt", "bar.txt", "baz.txt"] 

如果你通过这个线成File.stream!/3的东西,它尝试添加所有这些值在一起。

File.stream! ["foo.txt", "bar.txt", "baz.txt"] 
%File.Stream{line_or_bytes: :line, modes: [:raw, :read_ahead, :binary], 
path: "foo.txtbar.txtbaz.txt", raw: true} 

正如你所看到的,它认为你要访问的路径是"foo.txtbar.txtbaz.txt",这是不正确的,所有的连接在一起的“路径”。

为了访问所有这些文件,你将不得不自行运行每一个文件。

defmodule OpenFiles do 
    def file_open do 
    Path.wildcard("numfiles/*.txt") 
    end 

    def sort_num do 
    file_open() 
    |> Enum.map(fn file -> 
     file 
     |> File.stream!() 
     |> Stream.map(&String.strip/1) 
     |> Stream.map(&String.to_integer/1) 
     |> Enum.take(1) # This only takes the first line. This may or may not be what you want. 
    end) 
    |> List.flatten() 
    |> Enum.sort() 
    end 
end 

如上所述,如果您有很多文件(或大文件),则可能需要很长时间。但是,您可以通过使用并行映射实现而不是顺序Enum.map/2来缓解此问题。

+0

真的很好,详细的答案!非常感谢。是的,我认为平行地图的实施将是我最好的选择。 –

相关问题