Работа с S3 и облачными хранилищами в Kotlin: AWS SDK и MinIO

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

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

Начать курс

Работа с S3 и облачными хранилищами в Kotlin

Облачные объектные хранилища, совместимые с протоколом Amazon S3 (Simple Storage Service), стали стандартом де-факто для хранения неструктурированных данных: изображений, видео, логов, бэкапов и артефактов сборки. В экосистеме Kotlin (JVM, Android, Kotlin Multiplatform) для взаимодействия с S3 используются два основных подхода: официальный AWS SDK for Java/Kotlin и легковесный MinIO Java SDK. В этой статье разберём оба варианта, покажем примеры кода и дадим рекомендации по выбору.

1. AWS SDK for Java (Kotlin)

Официальный SDK от Amazon поддерживает все возможности S3, включая многопоточную загрузку, управление жизненным циклом, версионирование и шифрование. Для Kotlin достаточно добавить зависимость в build.gradle.kts:

dependencies {
    implementation("software.amazon.awssdk:s3:2.27.0")
    implementation("software.amazon.awssdk:auth:2.27.0")
}

Базовый пример загрузки файла в S3 bucket:

import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.PutObjectRequest
import java.nio.file.Paths

fun main() {
    val credentials = AwsBasicCredentials.create("ACCESS_KEY", "SECRET_KEY")
    val s3 = S3Client.builder()
        .region(Region.EU_CENTRAL_1)
        .credentialsProvider(StaticCredentialsProvider.create(credentials))
        .build()

    val request = PutObjectRequest.builder()
        .bucket("my-bucket")
        .key("uploads/photo.jpg")
        .contentType("image/jpeg")
        .build()

    s3.putObject(request, Paths.get("/local/path/photo.jpg"))
    println("Файл загружен")
}

Скачивание объекта:

import software.amazon.awssdk.services.s3.model.GetObjectRequest

val getRequest = GetObjectRequest.builder()
    .bucket("my-bucket")
    .key("uploads/photo.jpg")
    .build()

s3.getObject(getRequest, Paths.get("/local/download/photo.jpg"))

2. MinIO Java SDK (S3-совместимое хранилище)

MinIO — это высокопроизводительное объектное хранилище с открытым исходным кодом, полностью совместимое с S3 API. Его SDK подходит для работы как с локальным MinIO, так и с AWS S3, DigitalOcean Spaces, Yandex Object Storage и другими провайдерами. Добавьте зависимость:

dependencies {
    implementation("io.minio:minio:8.5.10")
}

Пример загрузки файла через MinIO SDK:

import io.minio.MinioClient
import io.minio.PutObjectArgs
import java.io.FileInputStream

fun main() {
    val minioClient = MinioClient.builder()
        .endpoint("https://play.min.io")
        .credentials("minioadmin", "minioadmin")
        .build()

    val inputStream = FileInputStream("/local/data/report.pdf")
    minioClient.putObject(
        PutObjectArgs.builder()
            .bucket("documents")
            .`object`("reports/2024/report.pdf")
            .stream(inputStream, inputStream.available(), -1)
            .contentType("application/pdf")
            .build()
    )
    println("Файл загружен в MinIO")
}

Скачивание через MinIO:

import io.minio.GetObjectArgs
import java.io.FileOutputStream

val getArgs = GetObjectArgs.builder()
    .bucket("documents")
    .`object`("reports/2024/report.pdf")
    .build()

val response = minioClient.getObject(getArgs)
response.use { stream ->
    FileOutputStream("/local/download/report.pdf").use { output ->
        stream.transferTo(output)
    }
}

3. Работа с публичными ссылками и сроками действия

Генерация временной ссылки (presigned URL) для скачивания без авторизации:

import software.amazon.awssdk.services.s3.model.GetObjectRequest
import software.amazon.awssdk.services.s3.presigner.S3Presigner
import java.time.Duration

val presigner = S3Presigner.builder()
    .region(Region.EU_CENTRAL_1)
    .credentialsProvider(StaticCredentialsProvider.create(credentials))
    .build()

val presignedRequest = presigner.presignGetObject { builder ->
    builder.getObjectRequest { req ->
        req.bucket("my-bucket")
            .key("uploads/photo.jpg")
    }
    .signatureDuration(Duration.ofHours(1))
}

println("Ссылка действительна 1 час: ${presignedRequest.url()}")

4. Рекомендации по выбору

  • AWS SDK — используйте, если работаете исключительно с AWS S3 и нужны полные возможности (CRR, Glacier, S3 Select).
  • MinIO SDK — предпочтителен

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