写在前面:
这是关于HDFS的api org.apache.hadoop.fs 小科普和吐槽,不过这个问题没有看过类似的,有一点提的价值。这个问题是实现需求:移动一个文件从一个目录到另一个目录。
实现方案
实现了后确实很简单,先创建对象,然后调用api就行。
/**
* 获取hdfs的文件系统对象
*
* @return FileSystem
* @throws IOException 打开HDFS文件系统异常
*/
public static FileSystem createFileSystemInstance() throws IOException {
Configuration conf = new Configuration();
return FileSystem.get(conf);
}
/**
* 移动hdfs上目录或文件到
* @param path 当前路径
* @param newPath 目标路径
* @return 是否移动成功
*/
public static boolean mv(String path,String newPath) {
boolean result = false;
FileSystem fs = null;
try {
fs = HDFSUtil.createFileSystemInstance();
if (!fs.exists(new Path(newPath))){
result=fs.rename(new Path(path),new Path(newPath));
}else {
LOGGER.warn("HDFS上目录: {} 被占用!",newPath);
}
} catch (Exception e) {
LOGGER.error("移动HDFS上目录:{} 失败!", path, e);
} finally {
//close(fs);
}
return result;
}
但调用的api十分有趣:rename,没错 就是重命名,尤其是linux的移动命令都是 hadoop fs -mv的时候。但最后就是这个重命名的api实现了需求(真的迷)
最开始在org.apache.hadoop.fs 找到两个与移动相关的api moveToLocalFile和 moveFromLocalFile 会在运行中显示找不到源文件,我觉得这两个api的作用是用在本机和集群之间的文件传输(待验证),但显然无法作用于hdfs系统的文件之间。
11.9补充
实际上有更好的实现,可以完成模糊查询数据追加等操作
/**
*@param prePath 需要合并的文件目录
* @param resPath 合并输出的文件名
* 合并文件 读取文件的目录 然后依次读文件并合并输出到一个文件中,并删除原文件
* 不处理递归
*/
public static void mergeFile(String prePath, String resPath) throws Exception {
FileSystem hdfs = HDFSUtil.createFileSystemInstance();
//获取文件目录(采用模糊查询的方法)
FileStatus[] fileStatuses = hdfs.globStatus(new Path(prePath));
//创建文件输出流
FSDataOutputStream fsOutStream = hdfs.create(new Path(resPath), true);
try {
for (FileStatus fs : fileStatuses) {
Path tmpPath = fs.getPath();
Boolean isFile = fs.isDirectory() ? false : true;
//只操作文件
if (isFile) {
System.out.println(tmpPath.getName());
//打开文件流
FSDataInputStream inStream = hdfs.open(tmpPath);
//读取文件内容到输出文件流
IOUtils.copyBytes(inStream, fsOutStream, 4096, false);
//关闭临时的输入流
IOUtils.closeStream(inStream);
//删除原文件,去掉后就是不删除原文件
hdfs.delete(tmpPath, true);
}
}
} catch (Exception ex) {
System.out.println(ex.toString());
} finally {
//关闭输出流
// IOUtils.closeStream(fsOutStream);
}
}