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.

Tags:

Elixir