How to read from post param?

287 views Asked by At

I need to parse text file. This file is in post param. I have code like this:

upload_file('POST', []) ->
    File = Req:post_param("file"),

What should I do next? How to parse it?

2

There are 2 answers

3
Berzemus On BEST ANSWER

What's inside Req:post_param("file") ?

You assume it's a path to a file: have you checked the value of File ?

Anyway, it's Req:post_files/0 you are probably looking for:

[{_, _FileName, TempLocation, _Size}|_] = Req:post_files(),
{ok,Data} = file:read_file(TempLocation),

It's also probably a Bad Idea to leave the file at it's temporary location, you'd better find a more suitable place to store them.


It seems the uploaded_file record has 5 fields now (for 10 months by now).

This is the updated example, with the fifth field:

[{_, _FileName, TempLocation, _Size, _Name}|_] = Req:post_files(),
{ok,Data} = file:read_file(TempLocation),

Oh, and because it's a record, following example should work even if the definition gets updated once again:

[File|_] = Req:post_files(),
{ok,Data} = file:read_file(File#uploaded_file.temp_file),

Another warning: the code above, as any erlanger will see, only deals with the first and, probably most of the times, only uploaded file. Should more files be uploaded at the same time, these would be ignored.

3
Pascal On

The answer really depend on the content of "File". for example if the file content a string with respecting erlang syntax such as:

[{{20,4},0},
 {{10,5},0},
 {{24,1},0},
 {{22,1},0},
 {{10,6},0}].

can be read with this code:

File = Req:post_param("file"),
{ok,B} = file:read_file(File),
{ok,Tokens,_} = erl_scan:string(binary_to_list(B)),
{ok,Term} = erl_parse:parse_term(Tokens),
%% at this point Term = [{{20,4},0},{{10,5},0},{{24,1},0},{{22,1},0},{{10,6},0}]

[Edit]

the Erlang libraries use most of the time tuple as return value. It can help to manage the normal case and error cases. In the previous code, all lines are "pattern matched" to the success case only. That means that it will crash if any of the operation fails. If the surrounding code cath the error you will be able to manage the error case, otherwise the process will simply die reporting a badmatch error.

I chose this implementation because at this level of code, there is nothing that can be done to deal with an error. {{badmatch,{error,enoent}} simply means that the return value of file:read_file(File) is not of the form {ok,B} as expected, but is {error,enoent}, which means that the file File does not exist in the current path.

extract of the documentation

read_file(Filename) -> {ok, Binary} | {error, Reason}
Types:
Filename = name()
Binary = binary()
Reason = posix() | badarg | terminated | system_limit

Returns {ok, Binary}, where Binary is a binary data object that contains the contents of Filename, or {error, Reason} if an error occurs.

Typical error reasons:
enoent
    The file does not exist.
eacces
    Missing permission for reading the file, or for searching one of the parent directories.
eisdir
    The named file is a directory.
enotdir
    A component of the file name is not a directory. On some platforms, enoent is returned instead.
enomem
    There is not enough memory for the contents of the file.

In my opinion the calling code should manage this case if it is a real use case, for example File comes from a user interface, or let the error unmanaged if this case should not happen. In your case you could do

try File_to_term(Params) % call the above code with significant Params
catch
    error:{badmatch,{error,enoent}} -> file_does_not_exist_management();
    error:{badmatch,{error,eacces}} -> file_access_management();
    error:{badmatch,{error,Error}} -> file_error(Error)
end