Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Download large files in rust with progress bar using reqwest, future_util and indicatif
// you need this in your cargo.toml
// reqwest = { version = "0.11.3", features = ["stream"] }
// futures-util = "0.3.14"
// indicatif = "0.15.0"
use std::cmp::min;
use std::fs::File;
use std::io::Write;
use reqwest::Client;
use indicatif::{ProgressBar, ProgressStyle};
use futures_util::StreamExt;
pub async fn download_file(client: &Client, url: &str, path: &str) -> Result<(), String> {
// Reqwest setup
let res = client
.or(Err(format!("Failed to GET from '{}'", &url)))?;
let total_size = res
.ok_or(format!("Failed to get content length from '{}'", &url))?;
// Indicatif setup
let pb = ProgressBar::new(total_size);
.template("{msg}\n{} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
pb.set_message(&format!("Downloading {}", url));
// download chunks
let mut file = File::create(path).or(Err(format!("Failed to create file '{}'", path)))?;
let mut downloaded: u64 = 0;
let mut stream = res.bytes_stream();
while let Some(item) = {
let chunk = item.or(Err(format!("Error while downloading file")))?;
.or(Err(format!("Error while writing to file")))?;
let new = min(downloaded + (chunk.len() as u64), total_size);
downloaded = new;
pb.finish_with_message(&format!("Downloaded {} to {}", url, path));
return Ok(());
Copy link

lennartkloock commented Feb 10, 2022

Yes, I agree. It is important to use write_all instead of write, otherwise it won't work

Copy link

giuliano-oliveira commented Feb 10, 2022

Makes perfect sense, thanks @orhun @lennartkloock

Copy link

Tails commented Jun 23, 2022

Does .get().send().await not immediately retrieve the whole response body to memory?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment