file:write_file / 2在给定二进制文件时返回{error,badarg}

时间:2014-12-20 11:11:58

标签: erlang

我坚持使用Joe Armstrong编写的Erlang编程练习(第2版)。第二章介绍了一个简短的程序,它在本地运行文件服务器及其客户端。该示例仅允许客户端列出并从服务器获取文件。练习需要您通过添加put_file功能来增强它。

所以我添加了一个case条件来接收带有put_file atom的消息,并用与源相同的文件名写入它们。然后我向客户端添加了一个函数来读取文件的内容并将其名称和内容发送到服务器。

不幸的是,每次消息到达服务器时,服务器都会告诉我我将错误的参数传递给file:write_file/2函数(它返回{error, badarg})。 假设文件名参数是正确的,我已检查过文档,file:read_file/1返回二进制文件,而file:write_file/2获取一个iodata,如果我正确解释文档,则可以是一个iolist或二进制。

iodata = iolist() | binary()

我说这些类型是正确的,但我很确定我错过了什么。

这是代码。

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).

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.

2 个答案:

答案 0 :(得分:3)

file:read_file / 1返回{ok,Binary}或{error,Reason}。您在put_file消息中将其作为二进制文件传递,这就是当您尝试将其提供给file:write_file / 2时出现错误的原因。将“Binary = file:read_file(File)”更改为“{ok,Binary} = file:read_file(File)”,它应该可以正常工作。

答案 1 :(得分:0)

客户端的实现很糟糕,因为Binary就像在Erlang中的String,函数write_file不需要文件描述符,它需要一个Message,然后如果我们重写客户端函数就像:

put_file(Server, File, Message) ->
  Server ! {self(), {put_file, File, Message}},
  receive
    {Server, ok} ->
      ls(Server);
    {Server, {error, Reason}} ->
      Reason
  end.

这就足够了,呼叫是:

afile_client:put_file(Client,"lola","This message is in file."

我在客户端做了这个练习:

{Client,{put_file,File,Message}} ->
          Full=filename:join(Dir,File),
          Client ! {self(),file:write_file(Full,Message)}

在服务器中:

put_file(Server,File,Message) ->
        Server ! {self(),{put_file,File,Message}},
        receive
                {Server,Content}  ->
                        Content
        end.

的问候。