Работа с S3 и облачными хранилищами в Rust: библиотека aws-sdk-s3

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с S3 и облачными хранилищами в Rust: библиотека aws-sdk-s3

Облачные объектные хранилища, такие как Amazon S3, стали стандартом для хранения и доставки файлов, бэкапов и медиа-контента. Rust, как язык системного программирования, предлагает мощные и безопасные инструменты для интеграции с этими сервисами. Основной библиотекой является aws-sdk-s3 — официальный SDK от Amazon для Rust.

В этой статье мы разберём, как настроить проект, выполнить базовые операции (загрузка, скачивание, удаление) и работать с S3-совместимыми хранилищами (например, MinIO или Yandex Object Storage).

Установка и настройка

Добавьте в Cargo.toml:

[dependencies]
aws-sdk-s3 = "1.0"
aws-config = "1.0"
tokio = { version = "1", features = ["full"] }

Для аутентификации используются переменные окружения или файл ~/.aws/credentials:

export AWS_ACCESS_KEY_ID="your_access_key"
export AWS_SECRET_ACCESS_KEY="your_secret_key"
export AWS_DEFAULT_REGION="us-east-1"

Инициализация клиента

Создадим асинхронный клиент S3:

use aws_sdk_s3::Client;
use aws_config::load_defaults;
use aws_config::BehaviorVersion;

#[tokio::main]
async fn main() {
    let config = load_defaults(BehaviorVersion::latest()).await;
    let client = Client::new(&config);
    // теперь client готов к работе
}

Загрузка файла в S3 (Upload)

Для загрузки данных используется метод put_object. Данные можно передать как байты или из потока:

use aws_sdk_s3::primitives::ByteStream;
use std::path::Path;

async fn upload_file(client: &Client, bucket: &str, key: &str, file_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let body = ByteStream::from_path(Path::new(file_path)).await?;
    
    client
        .put_object()
        .bucket(bucket)
        .key(key)
        .body(body)
        .send()
        .await?;
    
    println!("Файл {} загружен в {}/{}", file_path, bucket, key);
    Ok(())
}

Скачивание файла (Get Object)

Чтобы получить объект и сохранить его локально:

use tokio::io::AsyncWriteExt;

async fn download_file(client: &Client, bucket: &str, key: &str, dest_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let response = client
        .get_object()
        .bucket(bucket)
        .key(key)
        .send()
        .await?;
    
    let mut file = tokio::fs::File::create(dest_path).await?;
    let mut stream = response.body;
    
    while let Some(bytes) = stream.try_next().await? {
        file.write_all(&bytes).await?;
    }
    
    println!("Файл {}/{} скачан в {}", bucket, key, dest_path);
    Ok(())
}

Список объектов в бакете

Получить список файлов (ключей) в бакете:

async fn list_objects(client: &Client, bucket: &str) -> Result<(), Box<dyn std::error::Error>> {
    let objects = client
        .list_objects_v2()
        .bucket(bucket)
        .send()
        .await?;
    
    if let Some(contents) = objects.contents {
        for obj in contents {
            if let Some(key) = obj.key {
                println!("- {}", key);
            }
        }
    }
    Ok(())
}

Удаление объекта

async fn delete_object(client: &Client, bucket: &str, key: &str) -> Result<(), Box<dyn std::error::Error>> {
    client
        .delete_object()
        .bucket(bucket)
        .key(key)
        .send()
        .await?;
    
    println!("Объект {}/{} удалён", bucket, key);
    Ok(())
}

Работа с MinIO и другими S3-совместимыми хранилищами

Чтобы подключиться к MinIO (локальный S3-эмулятор) или Yandex Object Storage, нужно переопределить endpoint:

use aws_sdk_s3::config::Region;
use aws_sdk_s3::config::Credentials;

async fn create_minio_client() -> Client {
    let credentials = Credentials::new("minioadmin", "minioadmin", None, None, "minio");
    
    let config = aws_config::from_env()
        .endpoint_url("http://localhost:9000")  // URL MinIO
        .region(Region::new("us-east-1"))
        .credentials_provider(credentials)
        .load()
        .await;
    
    Client::new(&config)
}

                
    
    

Рекомендаций