Elixir - Download a File (Image) from a URL
Have a look at httpoison, an HTTP client for Elixir. You can just issue a GET
request to the url pointing to the image (or file, it's irrelevant):
%HTTPoison.Response{body: body} = HTTPoison.get!("http://example.com/img.png")
HTTPoison.get!/1
returns an HTTPoison.Response
struct; I matched on that struct in order to get the body of the response. Now the body
variables contains the image data (which is just a binary); you can write it to a file:
File.write!("/tmp/image.png", body)
and there you go :).
This is obviously possible even without using httpoison, but you would have to deal with raw TCP connections (look at the gen_tcp
Erlang module), parsing of the HTTP response and a bunch of stuff you usually don't want to do manually.
Whoops, forgot to mention the httpc
Erlang module (included in the stdlib!), which makes this very simple without the need for a dependency like HTTPoison:
Application.ensure_all_started :inets
{:ok, resp} = :httpc.request(:get, {'http://example.com/my_image.jpg', []}, [], [body_format: :binary])
{{_, 200, 'OK'}, _headers, body} = resp
File.write!("/tmp/my_image.jpg", body)
Download method provided by @whatyouhide works but have drawbacks:
- The whole response is loading to the RAM, and only after then is going to the
File.write/1
. You have to choose async HTTPoison request to escape high memory consumption. - There is no restriction of the file size to download. If you handle, saying, user input and then you're trying to download any file user provided, your server can go down for downloading a file which has 1TB size.
I created download elixir package to bypass these cons.
It has nice syntax and well-tested. Just type
Download.from(url, [path: "/where/to/save", max_file_size: integer_in_bytes])
To stream the URL directly to a file with httpc:
:inets.start()
:ssl.start()
{:ok, :saved_to_file} = :httpc.request(:get, {'https://elixir-lang.org/images/logo/logo.png', []}, [], [stream: '/tmp/elixir'])
I downloaded a 183MB file and the observer showed that memory use never exceeded 25MB. Note the single quoted strings! We cannot pass Elixir strings to this Erlang library.