Import AWS SDK for Kotlin

Ensure that Java 11 or a newer version and Gradle are installed.

Add the following code in the dependencies block of your build.gradle.kts file

dependencies {
    implementation("aws.sdk.kotlin:s3:1.0.50")
    implementation("aws.sdk.kotlin:sts:1.0.50")
}

Here's the complete example of the build.gradle.kts file (Kotlin DSL version) with the com.sufy.s3.examples.App package:

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.9.0"
    application
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("aws.sdk.kotlin:s3:1.0.50")
    implementation("aws.sdk.kotlin:sts:1.0.50")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    implementation("com.google.guava:guava:32.1.1-jre")
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(11))
    }
}

application {
    mainClass.set("com.sufy.s3.examples.AppKt")
}

tasks.named<Test>("test") {
    useJUnitPlatform()
}

For each code example that follows,create the code under the app/src/main/kotlin/com/sufy/s3/examples/App.kt ,then execute

gradle run

UploadObject

Client-side upload

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.PutObjectRequest
import aws.sdk.kotlin.services.s3.presigners.presignPutObject
import aws.smithy.kotlin.runtime.net.url.Url
import kotlin.time.Duration.Companion.days
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val putObjectRequest = PutObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
    }
    val presignedRequest = s3Client.presignPutObject(putObjectRequest, 1.days)
    println(presignedRequest.url)
}

This code will generate a pre-signed client-side upload URL, valid for 24 hours, which the client can use to send an PUT request and upload a file within the expiration time.

The following is an example of uploading a file using curl:

curl -X PUT --upload-file "<path/to/file>" "<presigned url>"

Server-side upload

PutObject(file)

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.PutObjectRequest
import aws.smithy.kotlin.runtime.content.ByteStream
import aws.smithy.kotlin.runtime.content.fromFile
import aws.smithy.kotlin.runtime.net.url.Url
import java.io.File
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val putObjectRequest = PutObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
        body = ByteStream.fromFile(File("<path/to/upload>"))
    }
    val presignedResponse = s3Client.putObject(putObjectRequest)
    println("ETag: ${presignedResponse.eTag}")
}

PutObject(stream)

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.PutObjectRequest
import aws.smithy.kotlin.runtime.content.ByteStream
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val putObjectRequest = PutObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
        body = ByteStream.fromString("Hello from sufy S3!")
    }
    val presignedResponse = s3Client.putObject(putObjectRequest)
    println("ETag: ${presignedResponse.eTag}")
}

MultipartUpload(file)

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.CompleteMultipartUploadRequest
import aws.sdk.kotlin.services.s3.model.CompletedPart
import aws.sdk.kotlin.services.s3.model.CreateMultipartUploadRequest
import aws.sdk.kotlin.services.s3.model.UploadPartRequest
import aws.smithy.kotlin.runtime.content.ByteStream
import aws.smithy.kotlin.runtime.net.url.Url
import java.io.File
import java.util.Vector
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val createMultipartUploadRequest = CreateMultipartUploadRequest {
        bucket = "<Bucket>"
        key = "<Key>"
    }
    val createMultipartUploadResponse = s3Client.createMultipartUpload(createMultipartUploadRequest)

    val PART_SIZE = 5 * 1024 * 1024 // part size is 5 MB
    val partBuf = ByteArray(PART_SIZE)
    val completedParts: Vector<CompletedPart> = Vector()
    // The example given here is a serial multipart upload. You can modify it to perform a parallel multipart upload to further improve the upload speed.
    File("<path/to/upload>").inputStream().buffered().use { file ->
        var pn = 1
        while (true) {
            val haveRead = file.read(partBuf)
            if (haveRead <= 0) {
                break
            }
            val uploadPartRequest = UploadPartRequest {
                bucket = createMultipartUploadRequest.bucket
                key = createMultipartUploadRequest.key
                uploadId = createMultipartUploadResponse.uploadId
                partNumber = pn
                body = ByteStream.fromBytes(partBuf.copyOf(haveRead))
            }
            val uploadPartResponse = s3Client.uploadPart(uploadPartRequest)
            completedParts.add(
                    CompletedPart {
                        eTag = uploadPartResponse.eTag
                        partNumber = pn
                    }
            )
            pn++
        }
    }
    val completeMultipartUploadRequest = CompleteMultipartUploadRequest {
        bucket = createMultipartUploadRequest.bucket
        key = createMultipartUploadRequest.key
        uploadId = createMultipartUploadResponse.uploadId
        multipartUpload { parts = completedParts }
    }
    val completeMultipartUploadResponse =
            s3Client.completeMultipartUpload(completeMultipartUploadRequest)
    println("ETag: ${completeMultipartUploadResponse.eTag}")
}

GetObject

Client-side get object

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.GetObjectRequest
import aws.sdk.kotlin.services.s3.presigners.presignGetObject
import aws.smithy.kotlin.runtime.net.url.Url
import kotlin.time.Duration.Companion.days
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val getObjectRequest = GetObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
    }
    val presignedRequest = s3Client.presignGetObject(getObjectRequest, 1.days)
    println(presignedRequest.url)
}

This code will generate a pre-signed client-side download URL, valid for 24 hours, which the client can use to send an GET request and download the file within the expiration time.

The following is an example of downloading a file using curl:

curl -o "<path/to/download>" "<presigned url>"

Server-side get object

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.GetObjectRequest
import aws.smithy.kotlin.runtime.content.writeToFile
import aws.smithy.kotlin.runtime.net.url.Url
import java.io.File
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val getObjectRequest = GetObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
    }
    s3Client.getObject(getObjectRequest) { resp ->
        resp.body?.writeToFile(File("<path/to/download>"))
        println("ETag: ${resp.eTag}")
    }
}

ObjectOperations

HeadObject

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.HeadObjectRequest
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val headObjectRequest = HeadObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
    }
    val headObjectResponse = s3Client.headObject(headObjectRequest)
    println("ETag: ${headObjectResponse.eTag}")
}

ChangeStorageClass

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.CopyObjectRequest
import aws.sdk.kotlin.services.s3.model.MetadataDirective
import aws.sdk.kotlin.services.s3.model.StorageClass
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val copyObjectRequest = CopyObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
        copySource = "/<Bucket>/<Key>"
        storageClass = StorageClass.Glacier
        metadataDirective = MetadataDirective.Replace
    }
    s3Client.copyObject(copyObjectRequest)
    println("Done")
}

CopyObject

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.CopyObjectRequest
import aws.sdk.kotlin.services.s3.model.MetadataDirective
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val copyObjectRequest = CopyObjectRequest {
        bucket = "<ToBucket>"
        key = "<ToKey>"
        copySource = "/<FromBucket>/<FromKey>"
        metadataDirective = MetadataDirective.Copy
    }
    s3Client.copyObject(copyObjectRequest)
    println("Done")
}

CopyObject(> 5GB)

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.CompleteMultipartUploadRequest
import aws.sdk.kotlin.services.s3.model.CompletedPart
import aws.sdk.kotlin.services.s3.model.CreateMultipartUploadRequest
import aws.sdk.kotlin.services.s3.model.HeadObjectRequest
import aws.sdk.kotlin.services.s3.model.UploadPartCopyRequest
import aws.smithy.kotlin.runtime.net.url.Url
import java.util.Vector
import kotlin.math.min
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }

    val headObjectRequest = HeadObjectRequest {
        bucket = "<FromBucket>"
        key = "<FromKey>"
    }
    val headObjectResponse = s3Client.headObject(headObjectRequest)

    val createMultipartUploadRequest = CreateMultipartUploadRequest {
        bucket = "<ToBucket>"
        key = "<ToKey>"
    }
    val createMultipartUploadResponse = s3Client.createMultipartUpload(createMultipartUploadRequest)

    val PART_SIZE = 5 * 1024 * 1024 // part size is 5 MB
    val completedParts: Vector<CompletedPart> = Vector()
    // The example given here is a serial multipart copy. You can modify it to perform a parallel multipart copy to further improve the copy speed.
    var pn = 1
    var copied: Long = 0
    while (copied < headObjectResponse.contentLength) {
        val partSize = min(headObjectResponse.contentLength - copied, PART_SIZE.toLong())
        val uploadPartCopyRequest = UploadPartCopyRequest {
            bucket = createMultipartUploadRequest.bucket
            key = createMultipartUploadRequest.key
            uploadId = createMultipartUploadResponse.uploadId
            partNumber = pn
            copySource = "/${headObjectRequest.bucket}/${headObjectRequest.key}"
            copySourceRange = "bytes=${copied}-${copied+partSize}"
        }
        val uploadPartCopyResponse = s3Client.uploadPartCopy(uploadPartCopyRequest)
        completedParts.add(
                CompletedPart {
                    eTag = uploadPartCopyResponse.copyPartResult!!.eTag
                    partNumber = pn
                }
        )
        pn++
        copied += partSize
    }
    val completeMultipartUploadRequest = CompleteMultipartUploadRequest {
        bucket = createMultipartUploadRequest.bucket
        key = createMultipartUploadRequest.key
        uploadId = createMultipartUploadResponse.uploadId
        multipartUpload { parts = completedParts }
    }
    val completeMultipartUploadResponse =
            s3Client.completeMultipartUpload(completeMultipartUploadRequest)
    println("ETag: ${completeMultipartUploadResponse.eTag}")
}

DeleteObject

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.DeleteObjectRequest
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val deleteObjectRequest = DeleteObjectRequest {
        bucket = "<Bucket>"
        key = "<Key>"
    }
    s3Client.deleteObject(deleteObjectRequest)
    println("Done")
}

ListObjects

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.ListObjectsV2Request
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val listObjectsV2Request = ListObjectsV2Request {
        bucket = "<Bucket>"
        prefix = "<KeyPrefix>"
    }
    val listObjectsV2Response = s3Client.listObjectsV2(listObjectsV2Request)
    for (content in listObjectsV2Response.contents!!) {
        println("Key: ${content.key}")
        println("ETag: ${content.eTag}")
    }
}

DeleteObjects

Create app/src/main/kotlin/com/sufy/s3/examples/App.kt

package com.sufy.s3.examples

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.DeleteObjectsRequest
import aws.sdk.kotlin.services.s3.model.ObjectIdentifier
import aws.smithy.kotlin.runtime.net.url.Url
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    val s3Client = S3Client {
        credentialsProvider = StaticCredentialsProvider {
            accessKeyId = "<AccessKey>"
            secretAccessKey = "<SecretKey>"
        }
        region = "ap-southeast-2" // Asia Pacific (Hanoi) RegionID
        endpointUrl = Url.parse("https://mos.ap-southeast-2.sufybkt.com") // Asia Pacific (Hanoi) Endpoint
    }
    val deleteObjectsRequest = DeleteObjectsRequest {
        bucket = "<Bucket>"
        delete {
            objects =
                    listOf(
                            ObjectIdentifier { key = "<Key1>" },
                            ObjectIdentifier { key = "<Key2>" },
                            ObjectIdentifier { key = "<Key3>" }
                    )
        }
    }
    s3Client.deleteObjects(deleteObjectsRequest)
    println("Done")
}