Работа с S3 и облачными хранилищами в Kotlin
В современной разработке на Kotlin часто возникает необходимость интеграции с облачными хранилищами, совместимыми с протоколом Amazon S3 (Simple Storage Service). Это могут быть AWS S3, MinIO, DigitalOcean Spaces, Yandex Object Storage и другие. В этой статье мы рассмотрим два основных подхода: использование официального AWS SDK для Kotlin и легковесного клиента на основе Ktor.
1. AWS SDK для Kotlin (aws-sdk-kotlin)
Официальный SDK от Amazon предоставляет типизированный и асинхронный API, полностью поддерживающий корутины Kotlin. Это наиболее полное решение для работы с S3.
Подключение зависимости
Добавьте в build.gradle.kts:
dependencies {
implementation("aws.sdk.kotlin:s3:1.0.0")
implementation("aws.smithy.kotlin:http-client-engine-ktor:1.0.0")
}
Инициализация клиента
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.*
suspend fun createClient(): S3Client = S3Client.fromEnvironment {
region = "ru-central1"
// Для MinIO или других S3-совместимых хранилищ:
endpointUrl = "https://storage.yandexcloud.net"
// Настройка через переменные окружения AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY
}
Загрузка файла (PutObject)
suspend fun uploadFile(client: S3Client, bucket: String, key: String, filePath: String) {
val fileBytes = java.io.File(filePath).readBytes()
client.putObject(
PutObjectRequest {
this.bucket = bucket
this.key = key
this.body = fileBytes.toByteArray()
}
)
println("Файл $key загружен в бакет $bucket")
}
Скачивание файла (GetObject)
suspend fun downloadFile(client: S3Client, bucket: String, key: String, savePath: String) {
val response = client.getObject(
GetObjectRequest {
this.bucket = bucket
this.key = key
}
)
val bytes = response.body?.readAll()
if (bytes != null) {
java.io.File(savePath).writeBytes(bytes)
println("Файл $key сохранён в $savePath")
}
}
Список объектов в бакете
suspend fun listObjects(client: S3Client, bucket: String): List<String> {
val response = client.listObjectsV2(
ListObjectsV2Request {
this.bucket = bucket
}
)
return response.contents?.map { it.key ?: "" } ?: emptyList()
}
2. Ktor S3 Client (легковесная альтернатива)
Если вам не нужна вся мощь AWS SDK, можно использовать Ktor вместе с библиотекой ktor-client-s3. Это даёт минимальный вес и полный контроль над HTTP-запросами.
Подключение
dependencies {
implementation("io.ktor:ktor-client-core:2.3.0")
implementation("io.ktor:ktor-client-cio:2.3.0")
implementation("io.ktor:ktor-client-content-negotiation:2.3.0")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.0")
// Для подписи запросов S3
implementation("io.ktor:ktor-client-auth:2.3.0")
}
Создание S3-клиента на Ktor
import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.utils.io.*
class S3KtorClient(
private val endpoint: String,
private val accessKey: String,
private val secretKey: String
) {
private val client = HttpClient {
install(io.ktor.client.plugins.auth.Auth) {
basic {
credentials {
username = accessKey
password = secretKey
}
}
}
}
suspend fun putObject(bucket: String, key: String, data: ByteArray) {
client.put("$endpoint/$bucket/$key") {
setBody(ByteReadChannel(data))
contentType(ContentType.Application.OctetStream)
}
}
suspend fun getObject(bucket: String, key: String): ByteArray {
val response = client.get("$endpoint/$bucket/$key")
return response.bodyAsChannel().readRemaining().readBytes()
}
suspend fun deleteObject(bucket: String, key: String) {
client.delete("$endpoint/$bucket/$key")
}
}
Пример использования
suspend fun main() {
val s3 = S3KtorClient(
endpoint = "https://storage.yandexcloud.net",
accessKey = System.getenv("ACCESS_KEY"),
secretKey = System.getenv("SECRET_KEY")
)
// Загрузка
s3.putObject("my-bucket", "docs/report