我一直在坚持 Joe Armstrong 编写的《Programming Erlang》(第二版)的第一个编程练习。第二章介绍了一个在文件服务器及其客户端本地运行的简短程序。该示例仅允许客户端列出并从服务器获取文件。该练习要求您通过添加功能来增强它put_file。
因此,我添加了一个 case 条件来接收带有put_file原子的消息,并使用与源相同的文件名写入它们。然后我向客户端添加了一个函数来读取文件的内容并将其名称和内容发送到服务器。
不幸的是,每次消息到达服务器时,服务器都会告诉我,我向函数传递了一个错误的参数file:write_file/2(它返回{error, badarg})。假设文件名参数是正确的,我检查了文档并file:read_file/1返回一个二进制文件,同时file:write_file/2接受一个 iodata,如果我正确解释了文档,它可以是 iolist 或二进制文件。
iodata = iolist() | binary()
Run Code Online (Sandbox Code Playgroud)
我想说这些类型是正确的,但我很确定我错过了一些东西。
这是代码。
afile_server.erl
-module(afile_server).
-export([start/1, loop/1]).
start(Dir) -> spawn(afile_server, loop, [Dir]).
loop(Dir) ->
receive
{Client, list_dir} ->
Client ! {self(), file:list_dir(Dir)};
{Client, {get_file, File}} ->
Full = full(Dir, File),
Client ! {self(), file:read_file(Full)};
{Client, {put_file, File, Binary}} ->
Full = full(Dir, File),
Client ! {self(), file:write_file(Full, Binary)}
end,
loop(Dir).
full(Dir, File) -> filename:join(Dir, File).
Run Code Online (Sandbox Code Playgroud)
afile_client.erl
-module(afile_client).
-export([ls/1, get_file/2, put_file/2]).
ls(Server) ->
Server ! {self(), list_dir},
receive
{Server, FileList} ->
FileList
end.
get_file(Server, File) ->
Server ! {self(), {get_file, File}},
receive
{Server, Content} ->
Content
end.
put_file(Server, File) ->
Binary = file:read_file(File),
Server ! {self(), {put_file, File, Binary}},
receive
{Server, ok} ->
ls(Server);
{Server, {error, Reason}} ->
Reason
end.
Run Code Online (Sandbox Code Playgroud)
file:read_file/1返回{ok, Binary}或{error, Reason}. Binary您按照消息中的方式传递此信息put_file,这就是为什么当您尝试将其传递给 时会收到错误file:write_file/2。
改变
Binary = file:read_file(File)
到
{ok, Binary} = file:read_file(File)
它应该有效。