Почему изображение PNG, загруженное reqwest, повреждено?

Я следую коду, упомянутому в Rust Cookbook по адресу https://rust-lang-nursery.github.io/rust-cookbook/web/clients/download.html, чтобы загрузить файл асинхронно с помощью HTTP-запроса GET.

Мой код выглядит следующим образом:

#[tokio::main]
async fn main() -> Result<()> {

    let object_path = "logos/rust-logo-512x512.png";
    let target = format!("https://www.rust-lang.org/{}", object_path);  
    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 object_prefix = &object_path[..object_path.rfind('/').unwrap()];
        let object_name = &object_path[object_path.rfind('/').unwrap()+1..];
        let output_dir = format!("{}/{}", env::current_dir().unwrap().to_str().unwrap().to_string(), object_prefix);
        fs::create_dir_all(output_dir.clone())?;

        println!("will be located under: '{}'", output_dir.clone());
                
        let output_fname = format!("{}/{}", output_dir, object_name);
        println!("Creating the file {}", output_fname);
        
        File::create(output_fname)?
        
    };
    let content =  response.text().await?;
    copy(&mut content.as_bytes(), &mut dest)?;
    Ok(())
}

Он создает каталоги и загружает файл. Однако, когда я открываю файл, он отображает ошибку поврежденного файла. Я также пытался использовать другой URL-адрес, но проблема с поврежденным файлом все еще существует.

Я что-то упустил в коде?


person Community    schedule 14.09.2020    source источник
comment
Вы загружаете ответ в виде текста, поэтому, естественно, он не сработает, потому что файлы PNG являются двоичными.   -  person hoz    schedule 14.09.2020
comment
используйте bytes вместо text   -  person Netwave    schedule 14.09.2020
comment
Я пробовал let content = response.bytes().await?; copy(&mut content, &mut dest)?;, но выдает ошибку `` copy (& mut content, & mut dest) ?; признак std :: io :: Read не реализован для bytes :: bytes :: Bytes ''   -  person    schedule 14.09.2020
comment
@test, используйте io::Cursor   -  person Netwave    schedule 14.09.2020


Ответы (2)


Просто используя bytes и _ 2_ тоже работают, и это проще:

let mut content =  Cursor::new(response.bytes().await?);
copy(&mut content, &mut dest)?;
person Netwave    schedule 14.09.2020

Замена

let content =  response.text().await?;
copy(&mut content.as_bytes(), &mut dest)?;

by

let content =  response.bytes().await?;
    
let mut pos = 0;
while pos < content.len() {
    let bytes_written = dest.write(&content[pos..])?;
    pos += bytes_written;
}

работал! :)

Пожалуйста, ответьте, если этот код неэффективен. Спасибо всем за помощь.

person Community    schedule 14.09.2020
comment
Проще использовать write_all: dest.write_all (&content)?; вместо делаем петлю вручную. - person Jmb; 14.09.2020