Работа с 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 — предпочтителен