Reputation: 12804
I'm stuck with the very first programming exercise of Programming Erlang (2nd ed.) by Joe Armstrong. The second chapter introduces a brief program that runs locally both a file server and its client. The example only allows the client to list and get files from the server. The exercise requires you to enhance it by adding a put_file
feature.
So I added a case condition to receive messages with the put_file
atom and write them with the same filename as the source. Then I added a function to the client to read the contents of a file and send its name and contents to the server.
Unfortunately, each time the message reaches the server, the server tells me that I'm passing a bad argument to the file:write_file/2
function (it returns {error, badarg}
).
Assuming that the filename parameter is correct, I've checked the documentation and file:read_file/1
returns a binary, while file:write_file/2
takes an iodata, which, if I interpreted the docs correctly, can either be an iolist or binary.
iodata = iolist() | binary()
I'd say the types are right but I'm pretty sure I'm missing something.
Here's the code.
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.
Upvotes: 5
Views: 1191
Reputation: 10557
file:read_file/1
returns {ok, Binary}
or {error, Reason}
. You are passing this as Binary
in the put_file
message, which is why you get an error when you try to give it to file:write_file/2
.
Change
Binary = file:read_file(File)
to
{ok, Binary} = file:read_file(File)
and it should work.
Upvotes: 5
Reputation: 1
The implementations the client was bad, because Binary is like to String in Erlang, the function write_file don't need a file descriptor , It needs a Message, then if we rewrite the client function like to :
put_file(Server, File, Message) ->
Server ! {self(), {put_file, File, Message}},
receive
{Server, ok} ->
ls(Server);
{Server, {error, Reason}} ->
Reason
end.
It's sufficient, and the call be :
afile_client:put_file(Client,"lola","This message is in file."
I did this exercise in client:
{Client,{put_file,File,Message}} ->
Full=filename:join(Dir,File),
Client ! {self(),file:write_file(Full,Message)}
In server:
put_file(Server,File,Message) ->
Server ! {self(),{put_file,File,Message}},
receive
{Server,Content} ->
Content
end.
Regards.
Upvotes: 0