Java Can';t从HDFS复制到S3A
我有一个类可以使用以下命令将目录内容从一个位置复制到另一个位置:Java Can';t从HDFS复制到S3A,java,hadoop,amazon-s3,hdfs,Java,Hadoop,Amazon S3,Hdfs,我有一个类可以使用以下命令将目录内容从一个位置复制到另一个位置: import org.apache.hadoop.conf.Configuration; 导入org.apache.hadoop.fs.FileStatus; 导入org.apache.hadoop.fs.FileSystem; 导入org.apache.hadoop.fs.FileUtil; 导入org.apache.hadoop.fs.LocatedFileStatus; 导入org.apache.hadoop.fs.Path
import org.apache.hadoop.conf.Configuration;
导入org.apache.hadoop.fs.FileStatus;
导入org.apache.hadoop.fs.FileSystem;
导入org.apache.hadoop.fs.FileUtil;
导入org.apache.hadoop.fs.LocatedFileStatus;
导入org.apache.hadoop.fs.Path;
导入org.apache.hadoop.fs.RemoteIterator;
类文件夹{
专用最终文件系统fs;
专用最终路径pth;
//…构造函数和其他方法
/**
*将内容(文件和子文件夹中的文件)复制到另一个文件夹。
*合并重叠的文件夹
*覆盖已经存在的文件
*@param将内容移动到的目标文件夹
*@失败时抛出IOException
*/
public void copyFilesTo(最终文件夹目标)引发IOException{
最终RemoteIterator iter=this.fs.listFiles(
这个.pth,
符合事实的
);
最终URI根=this.pth.toUri();
while(iter.hasNext()){
最终路径源=iter.next().getPath();
FileUtil.copy(
这个是.fs,
来源
destination.fs,
新路径(
destination.pth,
root.relativize(source.toUri()).toString()
),
错误的
符合事实的
this.fs.getConf()
);
}
}
}
该类在单元测试中使用本地(文件://
)目录时工作正常,
但是当我试图在Hadoop集群中使用它从HDFS复制文件时(hdfs:///tmp/result
)到AmazonS3(s3a://mybucket/out
)它不会复制任何内容,也不会抛出错误,只是默默地跳过复制
当我将同一个类(同时使用HDFS或S3a文件系统)用于另一个目的时,它工作正常,因此这里的配置和fs
引用应该可以
我做错了什么?如何将文件从HDFS正确复制到S3A
我正在使用Hadoop 2.7.3
更新 我在
copyFilesTo
方法中添加了更多日志,以记录根
、源
和目标
变量(并在不更改代码的情况下提取了rebase()
方法):
/**
*将内容(文件和子文件夹中的文件)复制到另一个文件夹。
*合并重叠的文件夹
*覆盖已经存在的文件
*@param dst文件夹,内容将移动到该文件夹
*@失败时抛出IOException
*/
public void copyFilesTo(最终文件夹dst)引发IOException{
Logger.info(
这是“copyFilesTo(%s):从%s fs=%s”,
dst,this,this.hdfs
);
最终RemoteIterator iter=this.hdfs.listFiles(
这个.pth,
符合事实的
);
最终URI根=this.pth.toUri();
Logger.info(这是“copyFilesTo(%s):root=%s”,dst,root);
while(iter.hasNext()){
最终路径源=iter.next().getPath();
最终路径目标=Folder.rebase(dst.Path(),this.Path(),source);
Logger.info(
这是“copyFilesTo(%s):src=%s target=%s”,
dst、源、目标
);
FileUtil.copy(
这个.hdfs,
来源
dst.hdfs,
目标
错误的
符合事实的
this.hdfs.getConf()
);
}
}
/**
*使用root将目标URI的基更改为新基
*作为共同的道路。
*@param base新基地
*@param root公共根
*@param-target要重新设置基础的目标
*@返回路径与新基
*/
静态路径重基(最终路径基、最终路径根、最终路径目标){
返回新路径(
base,root.toUri().relativize(target.toUri()).toString()
);
}
在集群中运行后,我得到了以下日志:
io.Folder: copyFilesTo(hdfs:///tmp/_dst): from hdfs:///tmp/_src fs=DFS[DFSClient[clientName=DFSClient_NONMAPREDUCE_182008924_1, ugi=hadoop (auth:SIMPLE)]]
io.Folder: copyFilesTo(hdfs:///tmp/_dst): root=hdfs:///tmp/_src
INFO io.Folder: copyFilesTo(hdfs:///tmp/_dst): src=hdfs://ip-172-31-2-12.us-east-2.compute.internal:8020/tmp/_src/one.file target=hdfs://ip-172-31-2-12.us-east-2.compute.internal:8020/tmp/_src/one.file
我在
rebase()
方法中本地化了错误的代码,它在EMR集群中运行时无法正常工作,因为RemoteIterator
正在以远程格式返回URI:hdfs://ip-172-31-2-12.us-east-2.compute.internal:8020/tmp/_src/one.file
但此方法需要格式hdfs:///tmp/_src/one.file
,这就是为什么它在本地使用文件://
FS。我没有看到任何明显的错误
我不确定这是否是最好的、完全正确的解决方案,但它对我很有效。其思想是在重定基址之前修复本地路径的主机和端口,工作的
重定基址
方法将是:
/**
*使用root将目标URI的基更改为新基
*作为共同的道路。
*@param base新基地
*@param root公共根
*@param-target要重新设置基础的目标
*@返回路径与新基
*@失败时抛出IOException
*/
@SuppressWarnings(“PMD.DefaultPackage”)
静态路径重基(最终路径基、最终路径根、最终路径目标)
抛出IOException{
最终URI=target.toUri();
试一试{
返回新路径(
新路径(
新的URIBuilder(base.toUri())
.setHost(uri.getHost())
.setPort(uri.getPort())
.build()
),
新路径(
新乌里别尔