Skip to content

Instantly share code, notes, and snippets.

@Tapanhaz
Forked from giuliano-macedo/download_file.rs
Created November 7, 2023 14:46
Show Gist options
  • Select an option

  • Save Tapanhaz/096e299bf060607b572d700e89a62529 to your computer and use it in GitHub Desktop.

Select an option

Save Tapanhaz/096e299bf060607b572d700e89a62529 to your computer and use it in GitHub Desktop.
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
.get(url)
.send()
.await
.or(Err(format!("Failed to GET from '{}'", &url)))?;
let total_size = res
.content_length()
.ok_or(format!("Failed to get content length from '{}'", &url))?;
// Indicatif setup
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
.progress_chars("#>-"));
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) = stream.next().await {
let chunk = item.or(Err(format!("Error while downloading file")))?;
file.write_all(&chunk)
.or(Err(format!("Error while writing to file")))?;
let new = min(downloaded + (chunk.len() as u64), total_size);
downloaded = new;
pb.set_position(new);
}
pb.finish_with_message(&format!("Downloaded {} to {}", url, path));
return Ok(());
}
@BongoPoyo
Copy link

BongoPoyo commented Jun 4, 2024

stds imported:

use std::io::{prelude::*, Bytes};
use std::fs::File;
use std::fs;
use std::io::BufReader;
use std::time::Instant;
use std::path::Path;
use futures::stream::StreamExt;
use reqwest::Client;
use indicatif::{ProgressBar, ProgressStyle};

My code is this

                            let pb = ProgressBar::new(total_size);
                            pb.set_style(ProgressStyle::default_bar()
                                .template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
                                .progress_chars("#>-")); // ERROR here
                            pb.set_message(&format!("Downloading  file {}", mb));

The compiler says

"no method named `progress_chars` found for enum `Result` in the current scope\nmethod not found in

Cargo.toml

error-chain = "0.12.4"
ftp = "3.0.1"
futures = "0.3.30"
futures-util = "0.3.30"
indicatif = "0.17.8"
reqwest = { version = "0.12.4", features = ["blocking", "stream"] }
tempfile = "3.10.1"
#ftp = { version = "<version>", features = ["secure"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

@Tapanhaz
Copy link
Author

Tapanhaz commented Jun 5, 2024

Use indicatif version 0.15.0.

@devklick
Copy link

devklick commented Sep 5, 2024

@HashirShazad

"no method named progress_chars found for enum Result in the current scope\nmethod not found in

indicatif seems to have been updated so that calling .template() now returns a Result. You can unwrap it by calling .template().unwrap() or propogate the error using .template()?, e.g:

let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
    .template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap()
    .progress_chars("#>-")); // ERROR here
pb.set_message(&format!("Downloading  file {}", mb));

@kaiser101
Copy link

Hi, both lines using the format macro are throwing compilation errors.

error[E0716]: temporary value dropped while borrowed
--> src\main.rs:26:21
|
26 | pb.set_message(&format!("Downloading {}", url));
| ----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for 'static
|
= note: this error originates in the macro format (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0716]: temporary value dropped while borrowed
--> src\main.rs:42:29
|
42 | pb.finish_with_message(&format!("Downloaded {} to {}", url, path));
| ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for 'static
|
= note: this error originates in the macro format (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try rustc --explain E0716.
error: could not compile rust_download_stream (bin "rust_download_stream") due to 2 previous errors

What am I missing here?

@GoodDay360
Copy link

@BongoPoyo
Copy link

:) I fixed it, but thanks.

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