在 Rust 中使用 S3 和云存储:aws-sdk-s3
兼容 Amazon S3 的云对象存储已成为存储文件、备份、静态资源和数据的事实标准。在 Rust 生态系统中,用于处理 S3 的官方 AWS SDK 是 aws-sdk-s3。该工具不仅允许连接到 Amazon S3,还可以连接到任何兼容 S3 的存储:MinIO、Yandex Object Storage、DigitalOcean Spaces、Cloudflare R2 等。
安装与配置
在 Cargo.toml 中添加以下依赖项:
[dependencies]aws-sdk-s3 = "1.15"aws-config = "1.1"tokio = { version = "1", features = ["full"] }anyhow = "1.0"身份验证可以使用环境变量、AWS 配置文件 (~/.aws/credentials) 或通过编程方式传递密钥。客户端的最小初始化如下所示:
use aws_sdk_s3::Client;use aws_config::meta::region::RegionProviderChain;
#[tokio::main]async fn main() -> Result<(), anyhow::Error> { let region_provider = RegionProviderChain::default_provider() .or_else("ru-central1"); let config = aws_config::from_env() .region(region_provider) .load() .await; let client = Client::new(&config); // 接下来使用 client 进行操作 Ok(())}S3 基本操作
创建存储桶
use aws_sdk_s3::model::BucketLocationConstraint;
let bucket_name = "my-rust-bucket";let constraint = BucketLocationConstraint::from("ru-central1");let _ = client .create_bucket() .bucket(bucket_name) .create_bucket_configuration( aws_sdk_s3::model::CreateBucketConfiguration::builder() .location_constraint(constraint) .build() ) .send() .await?;上传文件 (PutObject)
use aws_sdk_s3::primitives::ByteStream;use std::path::Path;
let file_path = "local_file.txt";let body = ByteStream::from_path(Path::new(file_path)).await?;
client .put_object() .bucket(bucket_name) .key("uploads/remote_file.txt") .body(body) .send() .await?;println!("文件已上传");下载文件 (GetObject)
use tokio::io::AsyncWriteExt;
let resp = client .get_object() .bucket(bucket_name) .key("uploads/remote_file.txt") .send() .await?;
let mut file = tokio::fs::File::create("downloaded.txt").await?;let mut stream = resp.body;while let Some(chunk) = stream.try_next().await? { file.write_all(&chunk).await?;}println!("文件已下载");列出存储桶中的对象
let objects = client .list_objects_v2() .bucket(bucket_name) .prefix("uploads/") .send() .await?;
for obj in objects.contents().unwrap_or_default() { println!("- {}", obj.key().unwrap_or("unknown"));}连接到 MinIO 和其他兼容 S3 的存储
要使用 MinIO(或任何其他非 AWS 存储),需要覆盖 endpoint 并禁用区域签名验证(如果需要)。以下是完整示例:
use aws_sdk_s3::{Client, Config, Credentials, Region};use aws_smithy_client::erase::DynConnector;use aws_smithy_client::hyper_ext;use http::Uri;
let creds = Credentials::new( "minioadmin", "minioadmin", None, None, "minio",);
let endpoint = Uri::from_static("http://localhost:9000");let region = Region::new("us-east-1");
let config = Config::builder() .credentials_provider(creds) .region(region) .endpoint_resolver(endpoint) .force_path_style(true) // 对 MinIO 很重要 .build();
let client = Client::from_conf(config);// 所有对 client 的操作现在都通过 MinIO 进行请注意