2016-05-07 44 views
4

我正在寫一個程序,從輸入流中讀取,即二郎:從輸入流中讀取一個有效的方式

erl -run p main -noshell -s erlang halt < input 

的問題是,它需要大量的時間來閱讀它(輸入流是巨大的)使用此讀取功能:

read_input(L) -> 
    case io:get_line("") of 
     eof -> 
      lists:reverse(L); 
     E0 -> 
      read_input([E0|L]) 
    end. 

我一直在尋找更有效的替代品,但我什麼也沒找到。我試圖用文件讀取

{ok, Binary} = file:read_file("input") 

這樣遠遠高效得多。問題是我必須在名稱未知的平臺上運行該程序,所以我需要一些替代方案來實現。另外,我不能選擇跑步時使用的標誌,例如標誌-noinput不能添加到命令行。

無論您給予什麼樣的幫助,都會受到歡迎。

+0

如果一次讀取整個文件是可以接受的,您似乎可以指出,爲什麼不只是'{ok,Binary} = file:read_file(InputFile)'?我不明白使用'cat'來複制輸入和讀取副本的意義。 –

+0

這是一個命令行應用程序嗎?程序是否總是像這樣從命令行調用?輸入流從哪裏來?讀取數據後發生了什麼? –

+0

@SteveVinoski我編輯了這個問題,以刪除貓的事情,因爲它是混亂。是的,我可以直接從文件中讀取它,但我不知道它的名字,所以這個解決方案只在測試時才起作用。 –

回答

3

雖然Steve'ssolution是最快的知道我的解決方案可以使用file模塊解決方案具有相當不錯的表現:

-module(p). 

-export([start/0]). 

-define(BLK_SIZE, 16384). 

start() -> 
    do(), 
    halt(). 

do() -> 
    Bin = read(), 
    io:format("~p~n", [byte_size(Bin)]). 

read() -> 
    ok = io:setopts(standard_io, [binary]), 
    read(<<>>). 

read(Acc) -> 
    case file:read(standard_io, ?BLK_SIZE) of 
     {ok, Data} -> 
      read(<<Acc/bytes, Data/bytes>>); 
     eof -> 
      Acc 
    end. 

它與調用如:

erl -noshell -s p < input 

注意這兩種方法都可用於面向行的輸入,使用端口{line, Max_Line_Size}選項或爲file模塊解決方案。自17版以來(如果我沒有記錯的話),我發現有file:read_line/1中存在固定的性能錯誤,所以現在是好的。無論如何,你不應該期待Perl的性能和舒適度。

+0

@ Hyney-pichi-Vychdil您的解決方案正是我所需要的。非常感謝!確實,[Steve的解決方案](http://stackoverflow.com/a/37091420/49197)更高效,但差別非常小。我不知道用這種方法可以在Erlang程序中引用標準輸入。非常有用,也很有趣。再次感謝。我希望你的回答能幫助更多有類似問題的人:) –

7

您可以使用open_port/2來打開stdin並從中讀取二進制文件。例如:

-module(p). 
-export([start/0]). 

start() -> 
    process_flag(trap_exit, true), 
    P = open_port({fd,0,1}, [in, binary]), 
    Bin = read(P,<<>>), 
    io:format("received ~p\n", [Bin]), 
    halt(0). 

read(P, Bin) -> 
    receive 
     {P, {data, Data}} -> 
      read(P, <<Bin/binary, Data/binary>>); 
     {'EXIT',P,_} -> 
      Bin 
    end. 

該代碼必須捕獲退出,以便知道在端口關閉時退出其讀取循環。本示例將所有內容都讀入從read/2函數返回的單個二進制文件中,然後將其打印出來並退出,但顯然您可以在實際應用程序中對二進制文件執行進一步的操作。

您可以像這樣運行的:

erl -noinput -s p < input 
+0

你的解決方案非常高效,但是它不能解決我的問題,因爲當從外部平臺進行調用時,我無法添加'noinput'標誌。 –

+2

你的問題表明你正在使用'-noshell'。爲什麼你可以使用它,但你不能使用'-noinput'?你真的需要在你的問題中明確你的要求。 –

+0

因爲我無法選擇運行時使用的標誌。我需要它來解決一個Hackerrank問題,在閱讀輸入時的性能是必須的。我只需點擊一個按鈕並等待結果。他們中的大多數由於超時而結束,並且在分析後我發現主要時間消費者是輸入讀數。您提出的解決方案效率驚人,但不幸的是在這種情況下不起作用。 –