Как сохранить файл, загруженный с 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 была вокруг, но не находилась в ней.
Смотрите также:
- Асинхронная запись потока фрагментов в файл с использованием гипер
- Как мне записать Futures::Stream на диск, предварительно не сохраняя его полностью в памяти?
Версии зависимостей
[dependencies]
rusoto_s3 = "0.43.0"
rusoto_core = "0.43.0"
tokio = { version = "0.2.21", features = ["macros"] }
futures = "0.3.5"