Skip to content

Instantly share code, notes, and snippets.

@foresta
Created March 5, 2023 10:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save foresta/0819ca7eb07da399a3db25c4123964ba to your computer and use it in GitHub Desktop.
Save foresta/0819ca7eb07da399a3db25c4123964ba to your computer and use it in GitHub Desktop.
File Download sample
[package]
name = "file-downloader"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0.11", features=["stream"]}
tokio = { version = "1.26.0", features=["fs", "full"]}
anyhow = "1.0.69"
futures = "0.3.26"
pbr = "1.1.1"
#[macro_use]
extern crate anyhow;
use anyhow::Result;
use futures::StreamExt;
use pbr::{ProgressBar, Units};
use tokio::io::AsyncWriteExt;
#[tokio::main]
async fn main() {
let url = "https://blog.foresta.me/404.html";
let filename = "blog-404.html";
if let Err(e) = download_file(url, filename).await {
println!("Error occurred: {:?}", e);
} else {
println!("Download Successfly!");
}
}
async fn download_file(url: &str, filepath: &str) -> Result<()> {
println!("Download Started: {}", url);
let client = reqwest::Client::new();
// send HEAD request for get content-length
let content_length = get_content_length(&client, url).await?;
// create file
let mut file = tokio::fs::File::create(filepath).await?;
// Initialize progressBar
let mut pb = ProgressBar::new(content_length);
pb.set_units(Units::Bytes);
pb.set_width(Some(100));
// send GET request for download
let mut stream = client.get(url).send().await?.bytes_stream();
while let Some(chunk_result) = stream.next().await {
let chunk = &chunk_result?;
// update progress bar
pb.add(chunk.len() as u64);
// write to file
file.write_all(&chunk).await?;
}
file.flush().await?;
println!("Download Finished: to {}", filepath);
Ok(())
}
async fn get_content_length(client: &reqwest::Client, url: &str) -> Result<u64> {
let head_result = client.head(url).send().await?;
let headers = head_result.headers();
let content_length_header = headers
.get("content-length")
.ok_or(anyhow!("failed to get content-length for {}", url))?;
let content_length = content_length_header.to_str()?.parse::<u64>()?;
Ok(content_length)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment