2017-02-20 45 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

真的很好,詳細的答案!非常感謝。是的,我認爲平行地圖的實施將是我最好的選擇。 –

相關問題