Erlang:以有效的方式从输入流中读取
Erlang: Read from an input stream in a efficient way
我正在编写一个从 输入 流读取的程序,即
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")
这样效率要高得多。问题是我必须在名称未知的平台上 运行 这个程序,所以我需要一些替代方法。另外,我不能 select 运行ning 时使用的标志,例如标志 -noinput 不能添加到命令行。
无论您能提供什么帮助,我们都将竭诚欢迎。
您可以使用 open_port/2
打开标准输入并从中读取二进制文件。例如:
-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
虽然 Steve's 是我所知最快的解决方案,但可以使用 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:read_line/1
模块解决方案 file
。自版本 17(如果我没记错的话)以来,我发现 file:read_line/1
中存在固定的性能错误,所以现在很好。无论如何,您不应该期望 Perl 的性能和舒适性。
我正在编写一个从 输入 流读取的程序,即
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")
这样效率要高得多。问题是我必须在名称未知的平台上 运行 这个程序,所以我需要一些替代方法。另外,我不能 select 运行ning 时使用的标志,例如标志 -noinput 不能添加到命令行。
无论您能提供什么帮助,我们都将竭诚欢迎。
您可以使用 open_port/2
打开标准输入并从中读取二进制文件。例如:
-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
虽然 Steve's 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:read_line/1
模块解决方案 file
。自版本 17(如果我没记错的话)以来,我发现 file:read_line/1
中存在固定的性能错误,所以现在很好。无论如何,您不应该期望 Perl 的性能和舒适性。