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

使用globStatus遍历S3桶时触发URISyntaxException问题求助

问题:globStatus遍历S3桶因特殊字符目录失败,寻求替代通配方法

我原本使用globStatus结合通配符*获取S3桶内所有文件和目录,但桶内存在名为env:的含特殊字符目录,导致globStatus执行失败。

相关代码

import org.apache.hadoop.fs.{FileStatus, FileSystem, Path}

val uri = validatePath("Bucket_path")
val fs = getFs(uri)
val fileStatuses = fs.globStatus(new Path(uri))

报错堆栈

Caused by: java.lang.IllegalArgumentException: java.net.URISyntaxException: Expected scheme-specific part at index 4: env:
at org.apache.hadoop.fs.Path.initialize(Path.java:263)
at org.apache.hadoop.fs.Path.<init>(Path.java:221)
at org.apache.hadoop.fs.Path.<init>(Path.java:129)
at org.apache.hadoop.fs.Globber.doGlob(Globber.java:338)
at org.apache.hadoop.fs.Globber.glob(Globber.java:202)
at org.apache.hadoop.fs.s3a.S3AFileSystem.globStatus(S3AFileSystem.java:4253)
at org.apache.hadoop.fs.s3a.S3AFileSystem.globStatus(S3AFileSystem.java:4233)
... 40 more
Caused by: java.net.URISyntaxException: Expected scheme-specific part at index 4: env:
at java.net.URI$Parser.fail(URI.java:2847)
at java.net.URI$Parser.failExpecting(URI.java:2853)
at java.net.URI$Parser.parse(URI.java:3056)
at java.net.URI.<init>(URI.java:746)
at org.apache.hadoop.fs.Path.initialize(Path.java:260)
... 50 more

补充说明

该问题在Hadoop Common的Jira工单中处于开放状态。


替代解决方案

1. 用listStatus遍历后手动过滤

放弃globStatus的自动通配,直接调用listStatus获取根目录下所有条目,再手动模拟通配规则筛选:

val rootPath = new Path(uri)
val allStatuses = fs.listStatus(rootPath)

// 模拟*通配:保留所有非隐藏的文件/目录
val filteredStatuses = allStatuses.filter(status => {
  val entryName = status.getPath.getName
  !entryName.startsWith(".")
})

如果需要更复杂的通配逻辑,可借助Hadoop的GlobPattern类做匹配:

import org.apache.hadoop.fs.GlobPattern

val globPattern = new GlobPattern("*")
val filteredStatuses = allStatuses.filter(status => {
  globPattern.matches(status.getPath.getName)
})

2. 临时转义特殊字符

针对env:这类被误判为URI协议的目录名,尝试对特殊字符进行URL转义(注意:该方法兼容性依赖Hadoop版本,仅作为临时 workaround):

// 转义冒号前的字符,避免被解析为URI scheme
val escapedUri = uri.replace("env:", "%65nv:")
val fileStatuses = fs.globStatus(new Path(escapedUri))

3. 改用S3原生SDK操作

绕开Hadoop FS API,直接使用AWS S3 SDK列出桶内对象,自行处理通配逻辑:

import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request

val s3Client = S3Client.create()
val listRequest = ListObjectsV2Request.builder()
  .bucket("your-bucket-name") // 替换为实际桶名
  .prefix("") // 空前缀表示遍历根目录
  .build()

val response = s3Client.listObjectsV2(listRequest)
// 过滤符合*通配的条目
val filteredEntries = response.contents().filter(obj => {
  val keyParts = obj.key().split("/")
  keyParts.headOption.forall(name => !name.startsWith("."))
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 05:30:43