2017-02-20 3 views
1

私は私の研究のためにエリクサーを教えていますが、私の研究では数十から数百のテキストファイルを開き、これらのファイルのデータを結合し、私は、ディレクトリにあるすべてのファイルをどのように開いて、これらすべてのファイルのデータにアクセスできるかを把握しようとしています。ループ内の100個のファイルを反復処理するのは非常に遅いため、forループは使用しないでください。 Streamモジュールは私の目的には理想的だと思いますが、どうやって使うのかはわかりません。エリクシルの複数のファイルからデータを開いて収集する

以下、テストコードがあります。それは乱数を含むファイルの束を開いて、ファイル内の数値の文字列を整数に変換し、それらをソートすることだけです。オープニングファイルの部分以外はすべて動作します。私は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機能は、一度に1つのファイルに対してのみ機能します。ワイルドカードを使用していて、一度に複数のファイルを収集すると、期待通りの動作をしません。

戻り値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

本当に素晴らしい詳細な回答です!本当にありがとう。はい、私は並列マップの実装が私の最善の策だと思います。 –

関連する問題