You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Scala下载S3存储桶中全部文件?获取文件而非目录

解决Scala批量下载S3文件的问题

老哥,我太懂你这个痛点了——S3所谓的「目录」其实都是前缀模拟出来的,很多时候直接调用list接口会把这些前缀当成条目返回,导致你拿不到真正的文件列表。下面给你一套完整的Scala解决方案,帮你搞定批量下载:

第一步:确认依赖

首先确保你的项目里引入了AWS SDK v2的S3依赖(v1已经过时,不推荐用了),如果是用SBT的话,在build.sbt里加:

libraryDependencies += "software.amazon.awssdk" % "s3" % "2.20.0"
libraryDependencies += "software.amazon.awssdk" % "regions" % "2.20.0"

第二步:获取所有真实文件对象

这个方法会自动处理分页(避免文件太多一次拉取不到),并且过滤掉那些模拟目录的前缀(也就是key以/结尾的条目):

import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.{ListObjectsV2Request, ListObjectsV2Response, S3Object}

def listAllS3Objects(bucketName: String, prefix: String = ""): List[S3Object] = {
  // 替换成你的S3桶所在区域
  val s3Client = S3Client.builder().region(Region.US_EAST_1).build()
  var continuationToken: String = null
  var allObjects = List.empty[S3Object]

  do {
    val request = ListObjectsV2Request.builder()
      .bucket(bucketName)
      .prefix(prefix) // 可选:指定前缀,只遍历该前缀下的文件
      .continuationToken(continuationToken)
      .build()

    val response: ListObjectsV2Response = s3Client.listObjectsV2(request)
    // 过滤掉模拟目录,只保留真实文件
    val validObjects = response.contents().stream()
      .filter(obj => !obj.key().endsWith("/"))
      .toList()

    allObjects = allObjects ++ validObjects
    continuationToken = response.nextContinuationToken()
  } while (continuationToken != null)

  s3Client.close()
  allObjects
}

第三步:批量下载文件

结合你已经能正常工作的单个文件下载逻辑,我们封装一个批量下载的方法,还会自动在本地创建对应的目录结构:

import java.nio.file.Paths
import software.amazon.awssdk.services.s3.model.GetObjectRequest

// 单个文件下载(可以复用你已有的逻辑,这里是标准实现)
def downloadSingleS3File(s3Client: S3Client, bucketName: String, objectKey: String, localRoot: String): Unit = {
  val getRequest = GetObjectRequest.builder()
    .bucket(bucketName)
    .key(objectKey)
    .build()

  // 根据S3的key在本地创建对应的路径,保持层级结构
  val localFilePath = Paths.get(localRoot, objectKey)
  // 自动创建父目录(如果不存在)
  java.nio.file.Files.createDirectories(localFilePath.getParent)

  // 下载文件到本地
  s3Client.getObject(getRequest, localFilePath)
}

// 批量下载入口方法
def batchDownloadFromS3(bucketName: String, prefix: String = "", localRootPath: String): Unit = {
  val s3Client = S3Client.builder().region(Region.US_EAST_1).build()
  val allFiles = listAllS3Objects(bucketName, prefix)

  println(s"找到 ${allFiles.size} 个待下载文件...")
  allFiles.foreach { file =>
    println(s"正在下载:${file.key()}")
    downloadSingleS3File(s3Client, bucketName, file.key(), localRootPath)
  }

  s3Client.close()
  println("所有文件下载完成!")
}

关键注意点

  • 区域替换:把代码里的Region.US_EAST_1换成你的S3桶实际所在的区域(比如Region.AP_SOUTHEAST_1对应新加坡区)。
  • 凭证配置:确保你的程序能拿到AWS凭证——可以通过环境变量、~/.aws/credentials文件,或者如果是在EC2/EKS上运行的话,直接用IAM角色。
  • 前缀控制:如果只需要下载桶里某个「目录」下的文件,给prefix参数传对应的路径(比如"reports/2024/"),就能只遍历该前缀下的文件。

内容的提问来源于stack exchange,提问作者Aryan Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:23:06