Scala/Spark通过S3FileSystem获取S3对象列表时遇文件不存在错误
先看你的代码和报错信息,问题出在路径解析、协议选择或者权限配置上,我给你拆解几个关键点:
你的执行代码:
val exists = s3FS.exists(new org.apache.hadoop.fs.Path("s3n://bucketname/Daily/DailyCash.TXT")) println(exists) val sels=s3FS.listFiles(new org.apache.hadoop.fs.Path("s3n://bucketname//Daily"),true) println(sels)
运行报错信息:
Exception in thread "main" java.io.FileNotFoundException: File s3n://bucketname/ does not exist.
at org.apache.hadoop.fs.s3.S3FileSystem.listStatus(S3FileSystem.java:194)
at org.apache.hadoop.fs.FileSystem.listStatus(FileSystem.java:1482)
at org.apache.hadoop.fs.FileSystem.listStatus(FileSystem.java:1522)
at org.apache.hadoop.fs.FileSystem$4.(FileSystem.java:1798)
at org.apache.hadoop.fs.FileSystem.listLocatedStatus(FileSystem.java:1797)
at org.apache.hadoop.fs.FileSystem.listLocatedStatus(FileSystem.java:1780)
at org.apache.hadoop.fs.FileSystem$5.(FileSystem.java:1842)
at org.apache.hadoop.fs.FileSystem.listFiles(FileSystem.java:1839)
问题排查与解决方案:
修正路径格式错误:你调用
listFiles时用的路径是s3n://bucketname//Daily,多了一个斜杠会让Hadoop的路径解析逻辑混乱,误以为要访问桶的根目录s3n://bucketname/,进而触发“不存在”的错误。把路径改成s3n://bucketname/Daily(单斜杠分隔)即可。更换为推荐的S3协议:
s3n是Hadoop早期支持的S3协议,现在官方更推荐使用s3a协议——它支持更大的文件(超过5GB)、更高效的操作逻辑,兼容性也更好。把所有路径里的s3n://替换成s3a://,同时确保你的项目依赖包含hadoop-aws包,并且提前配置好AWS凭证:// 初始化FileSystem前配置凭证 val conf = new Configuration() conf.set("fs.s3a.access.key", "你的AWS访问密钥") conf.set("fs.s3a.secret.key", "你的AWS秘密密钥") val s3FS = FileSystem.get(new URI("s3a://bucketname"), conf)验证权限配置:确认你的AWS账号/角色拥有访问该S3桶的必要权限,至少需要
s3:ListBucket(列出桶内对象)和s3:GetObject(获取对象内容)权限。如果是在集群环境(比如EMR),还要检查集群绑定的IAM角色是否包含这些权限。正确遍历文件列表:
listFiles返回的是RemoteIterator[LocatedFileStatus],直接println只能得到对象引用,看不到实际文件路径,你需要遍历迭代器来查看内容:val sels = s3FS.listFiles(new org.apache.hadoop.fs.Path("s3a://bucketname/Daily"), true) while (sels.hasNext) { val fileStatus = sels.next() println(s"找到文件:${fileStatus.getPath}") }
优先试试修正路径和更换协议,这两个是最常见的解决办法,如果还是不行再检查权限配置。
内容的提问来源于stack exchange,提问作者Ankit90

