Как сохранить файл, загруженный с S3 с Rusoto, на мой жесткий диск?

Я пытаюсь загрузить файл из корзины с Rusoto и получаю содержимое файла:

fn get_object(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.get_object(&get_req).sync().expect("Couldn't GET object");


    let stream = result.body.unwrap();
    let body = stream.concat2().wait().unwrap();

    assert!(body.len() > 0);
}

Как я могу сохранить это GetObjectOutput(result) объект в файл?

1 ответ

Решение

Ты почти там. Ваш код поместит объект в body, который является Vec<u8>,

Написать содержание body в файл:

use std::io::Write;
use std::fs::File;

let mut file = File::create("/path/to/my-object").expect("create failed");
file.write_all(&body).expect("failed to write body");

Rusoto теперь использует стандартные библиотечные фьючерсы и больше не предлагает sync метод, поэтому предыдущий ответ больше не действителен.

Чтение в память

use futures::stream::TryStreamExt;
use rusoto_core::Region;
use rusoto_s3::{GetObjectRequest, S3Client, S3};

type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;

const BUCKET_NAME: &str = "my very own bucket name";

#[tokio::main]
async fn main() -> Result<()> {
    let client = S3Client::new(Region::UsEast2);

    let mut object = client
        .get_object(GetObjectRequest {
            bucket: BUCKET_NAME.into(),
            ..Default::default()
        })
        .await?;

    let body = object.body.take().expect("The object has no body");

    let body = body.map_ok(|b| b.to_vec()).try_concat().await?;
    println!("body length: {}", body.len());

    Ok(())
}

AWS_ACCESS_KEY_ID а также AWS_SECRET_ACCESS_KEYнеобходимо указать. Я решил устанавливать переменные среды вне кода.

Потоковая передача в файл

use rusoto_core::Region;
use rusoto_s3::{GetObjectRequest, S3Client, S3};
use tokio::{fs::File, io};

type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;

const BUCKET_NAME: &str = "my very own bucket name";

#[tokio::main]
async fn main() -> Result<()> {
    let client = S3Client::new(Region::UsEast2);

    let mut object = client
        .get_object(GetObjectRequest {
            bucket: BUCKET_NAME.into(),
            ..Default::default()
        })
        .await?;

    let body = object.body.take().expect("The object has no body");

    let mut body = body.into_async_read();
    let mut file = File::create("/tmp/a-place-to-write").await?;
    io::copy(&mut body, &mut file).await?;

    Ok(())
}

Пока ByteStream имеет заманчивый into_blocking_read метод, я не рекомендую его использовать. Если вы попытаетесь использовать его внутри асинхронного контекста, вы получите панику, потому что он запускает вложенный исполнитель Tokio. Если вы используете его вне асинхронного контекста, он усечет данные, если вы не позаботитесь о том, чтобы среда выполнения async была вокруг, но не находилась в ней.

Смотрите также:

Версии зависимостей

[dependencies]
rusoto_s3 = "0.43.0"
rusoto_core = "0.43.0"
tokio = { version = "0.2.21", features = ["macros"] }
futures = "0.3.5"
Другие вопросы по тегам