Skip to content

Latest commit

 

History

History
231 lines (180 loc) · 9.07 KB

AWS_로컬 파일(하위디렉토리포함) 한꺼번에 S3에 업로드하기.md

File metadata and controls

231 lines (180 loc) · 9.07 KB

AWS_로컬 파일(하위디렉토리포함) 한꺼번에 S3에 업로드하기

전제조건

  • gradle
  • kotlin
  • jdk : aws-correto-11 (aws 오픈소스)

gradle 세팅

  1. 기본 세팅
implementation("com.amazonaws:aws-java-sdk-s3:1.12.52")
  1. 버전관리 용 세팅
    aws-sdk 라이브러리를 많이 사용한다면 한번에 버전관리를 할 수 있다 (관련 docs).
    bom 버전 확인하러 가기
    • 코틀린 4.6 버전 이상:

      dependencies {
          implementation("com.amazonaws:aws-java-sdk-bom:1.12.52")
          implementation("software.amazon.awssdk:s3")
      }
    • 코틀린 4.6 버전 이전:

      dependencyManagement {
          imports {
              mavenBom("software.amazon.awssdk:bom:1.12.52")
          }
      }
      dependencies {
          implementation("software.amazon.awssdk:s3")
      }


\

디렉토리 S3 업로더 코틀린으로 작성하기

1. 업로드할 S3 버킷과 연결하기 - TransferManagerBuilder 생성하기

S3 버킷에 접근 가능한 aws_access_key_idaws_secret_access_key, region 을 설정하여 AmazonS3ClientBuilder 를 만들고 한꺼번에 업로드 할 수 있는 TransferManagerBuilder 를 만들어 반환하기

fun createS3DirectoryClient(accessKeyId: String, secretAccessKey: String, region: String): TransferManager {
    val awsCredentials = AWSStaticCredentialsProvider(BasicAWSCredentials(accessKeyId, secretAccessKey))

    val s3Client:AmazonS3 = AmazonS3ClientBuilder.standard()
            .withCredentials(awsCredentials)
            .withRegion(Regions.fromName(region))
            .build()
    
    return TransferManagerBuilder.standard()
            .withS3Client(s3Client)
            .build()
}

\

2. S3 버킷에 업로드하는 부분 만들기 - basic

  1. 먼저 local_path 가 /d/test/uploader/ 라고 하자.
    uploader 내부에는 수많은 파일이 있고, 각 파일마다 2mb 를 넘지 않는다고 가정.
    (만약 파일 하나 하나의 사이즈가 크다면 다른 방식으로 해야 됨. 하단 참고부분에서 멀티파트 업로드를 사용한 객체 업로드 부분을 참고할 것.)

    \

  2. s3에 업로드 될 path 는 {bucket_name} path1/path2/upload/210831/ 이라고 가정.
    bucket_name = mand2 로 한다.
    default_path = /path1/path2/ 로 가정.
    참고로 s3 업로드시 해당 객체(경로)가 없어도 자동으로 생성되므로 먼저 객체를 만들어야하나? 하고 고민하지 않아도 된다. (내가 고민하다 삽질해봄..ㅎ)

    👀 주의사항
    각 path 앞, 뒤에 / 가 있다면 없애주자.
    예를들어 /mand2/path1/path2/.... 이라고 설정이 된다면 실제로 업로드 되지 않음.
    테스트 해보면 알겠지만 업로드 완료 라고 뜨지만 실제 s3에는 객체생성이 되지 않는다.

\

@JvmField val pathRegEx: Regex = Regex("^(/)|(/)$")

fun uploadDirectoryOfClient(s3DirectoryClient:TransferManager, defaultPath: String) {
    // 로컬 디렉토리 세팅
    val localPath = "/d/test/uploader/"
    val localDirectory = File(localPath)
    
    // s3 객체 경로 세팅
    val bucketName = "mand2"
    val s3Path = pathRegEx.replace(defaultPath, "")
    val s3UploadPath = "$s3Path/upload/210831"
    try {
        // 실제 업로드
        val uploadDirectory: MultipleFileUpload = s3DirectoryClient.uploadDirectory(
                bucketName,
                s3UploadPath,
                localDirectory,
                true
        )
        uploadDirectory.waitForCompletion()
        logger.info("[Uploader] Upload Directory to S3 Success !")
        
    } catch (e: AmazonServiceException) {
        logger.error("Amazon service error: {}, {}", e.message, e)
    } catch (e: AmazonClientException) {
        logger.error("Amazon client error: {}, {}", e.message, e)
    } catch (e: InterruptedException) {
        logger.error("Transfer interrupted: {}, {}", e.message, e)
    } finally {
        s3DirectoryClient.shutdownNow()
    }
}


\

3. S3 버킷에 업로드하는 부분 만들기 - advanced

위에 코드를 실행해보면 답답할 것이다. 얼마나 완료되었는지 확인을 못하므로..🤔
그러니 로그를 같이 남겨서 확인할 수 있게 해주자

@JvmField val pathRegEx: Regex = Regex("^(/)|(/)$")

fun uploadDirectoryOfClient(s3DirectoryClient:TransferManager, defaultPath: String) {
    // 로컬 디렉토리 세팅
    val localPath = "/d/test/uploader/"
    val localDirectory = File(localPath)
    
    // s3 객체 경로 세팅
    val bucketName = "mand2"
    val s3Path = pathRegEx.replace(defaultPath, "")
    val s3UploadPath = "$s3Path/upload/210831"

    var uploadProgressBar = StringBuffer() // 업로드 진행상황 log
    try {
        // 실제 업로드
        val uploadDirectory: MultipleFileUpload = s3DirectoryClient.uploadDirectory(
                bucketName,
                s3UploadPath,
                localDirectory,
                true
        )
        
        uploadProgressBar
                .append("[Running] upload progressing... start")
                .appendLine()

        while (!uploadDirectory.isDone) {
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                return;
            }
            val progress: TransferProgress = uploadDirectory.progress
            val pct: Double = progress.percentTransferred
            val pctFormat = DecimalFormat("##0.00")
            uploadProgressBar
                    .append("[Running] ${pctFormat.format(pct)}% upload progressing...")
                    .appendLine()
        }

        logger.info("[Uploader] Upload Directory to S3 Success !")
        
    } catch (e: AmazonServiceException) {
        logger.error("Amazon service error: {}, {}", e.message, e)
    } catch (e: AmazonClientException) {
        logger.error("Amazon client error: {}, {}", e.message, e)
    } catch (e: InterruptedException) {
        logger.error("Transfer interrupted: {}, {}", e.message, e)
    } finally {
        s3DirectoryClient.shutdownNow()
        logger.info(uploadProgressBar.toString())
    }
}


\

결과 예시

[Running] upload progressing... start
[Running] 0.35% upload progressing...
[Running] 0.70% upload progressing...
[Running] 1.06% upload progressing...
[Running] 1.44% upload progressing...
[Running] 1.80% upload progressing...
[Running] 2.15% upload progressing...
[Running] 2.52% upload progressing...
[Running] 6.81% upload progressing...
[Running] 11.00% upload progressing...
[Running] 15.00% upload progressing...
[Running] 19.12% upload progressing...
[Running] 23.31% upload progressing...


\

참고 주소