Download Binary File/Image (Rust)
use error_chain::error_chain;
use std::io::copy;
use std::fs::File;
use tempfile::Builder;
use std::io::Cursor;
error_chain! {
foreign_links {
Io(std::io::Error);
HttpRequest(reqwest::Error);
}
}
#[tokio::main]
async fn main() -> Result<()> {
let tmp_dir = Builder::new().prefix("example").tempdir()?;
let target = "https://www.rust-lang.org/logos/rust-logo-512x512.png";
let response = reqwest::get(target).await?;
let mut dest = {
let fname = response
.url()
.path_segments()
.and_then(|segments| segments.last())
.and_then(|name| if name.is_empty() { None } else { Some(name) })
.unwrap_or("tmp.bin");
println!("file to download: '{}'", fname);
// let fname = tmp_dir.path().join(fname); ! this line is commented out as temp files are removed on exit.
// This will download the file in cwd, so we can verify the content.
println!("will be located under: '{:?}'", fname);
File::create(fname)?
};
// let content = response.text().await?;
// copy(&mut content.as_bytes(), &mut dest)?;
let mut content = Cursor::new(response.bytes().await?);
copy(&mut content, &mut dest)?;
Ok(())
}
The Official Cook Book Sample Code is wrong.
Doesn't work. Instead of using .text()
, use .bytes()
and wrapped with Cursor
.
Cursor
is the main point. An experienced developer (but beginner in Rust) knows that converting binary file content to text then bytes is dangerous,
due to encoding issue; but wouldn't know about Cursor
.
Error Explained
std::io::Read
requires Read
, which Bytes
doesn't have. So Cursor
is needed.
Weird design for developer from another language.
the trait bound `bytes::bytes::Bytes: std::io::Read` is not satisfied
the trait `std::io::Read` is not implemented for `bytes::bytes::Bytes
main.rs(37, 5): required by a bound introduced by this call
copy.rs(55, 8): required by a bound in `std::io::copy`
No quick fixes available