1.使用Idea创建maven项目,并添加HDFS依赖
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.0.0</version>
</dependency>
2.HDFSUtil
这里主要在获得url时遇到了困难:url不正确的话,会报各种不同的错误
例如:
- UnsupportedOperationException at org.apache.hadoop.fs.http.AbstractHttpFile
- RPC response exceeds maximum data length
- java.net.UnknownHostException: nameservice1
- …
网上查找相关资料:URI的地址要跟core-site.xml中的fs.defaultFS一致
查看集群core-site.xml配置中fs.defaultFS没有配置9000端口,并且写上会报错
<property>
<name>fs.defaultFS</name>
<value>hdfs://nameservice1</value>
</property>
查看hdfs-site.xml中存在dfs.namenode.rpc-address.nameservice1.namenode244配置
<property>
<name>dfs.namenode.rpc-address.nameservice1.namenode244</name>
<value>qk-offline-hdp-18-17:8020</value>
</property>
将url改为8020可成功连接,另外这里18-17需要配置ip映射,或者使用ip
- 8020端口与9000端口的作用与配置:https://blog.csdn.net/m0_54850604/article/details/123740182
HDFSUtil代码:
package com.data.HDFS;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
/**
* Created by zdf on 2022/4/12 15:42
*/
public class HDFSUtil {
private static FileSystem fs;
/**
* 初始化FileSystem.
* 这里很坑,如果conf和url不对的话, 会报各种不同错误
*/
static{
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://10.129.18.17:8020");
try {
fs = FileSystem.get(new URI("hdfs://10.129.18.17:8020"),conf,"hadoop");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取fs
*/
public static FileSystem getFileSystem(){
return fs;
}
/**
* 查看路径的文件&文件夹
* @param path 目标路径
*/
public static void listAll(String path) throws FileNotFoundException, IllegalArgumentException, IOException {
FileStatus[] listStatus = fs.listStatus(new Path(path));
String flag = "d-- ";
for (FileStatus fstatus : listStatus) {
if (fstatus.isFile()){
flag = "f-- ";
}
System.out.println(flag + fstatus.getPath().getName());
}
}
/**
* HDFS文件下载到本地
* @param hdfsPath HDFS远程路径(到需要下载的文件)
* @param localPath 本地路径(到存放文件的文件夹)
*/
public static void downloadFileToLocal(String hdfsPath, String localPath) throws IllegalArgumentException, IOException {
//TODO 待优化
fs.copyToLocalFile(new Path(hdfsPath), new Path(localPath));
fs.close();
}
/**
* 本地上传文件到HDFS
* @param localPath 本地文件路径
* @param hdfsPath HDFS文件夹路径
*/
public static void addFileToHdfs(String localPath, String hdfsPath) throws Exception {
//TODO 待优化
Path src = new Path(localPath);
Path dst = new Path(hdfsPath);
fs.copyFromLocalFile(src, dst);
fs.close();
}
/**
* 递归列出给定路径下文件的的状态信息和块信息
* @param hdfsPath HDFS路径
*/
public static void listFiles(String hdfsPath) throws FileNotFoundException, IllegalArgumentException, IOException {
// 思考:为什么返回迭代器,而不是List之类的容器
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path(hdfsPath), true);
while (listFiles.hasNext()) {
LocatedFileStatus fileStatus = listFiles.next();
System.out.println(fileStatus.getPath().getName());
System.out.println(fileStatus.getBlockSize());
System.out.println(fileStatus.getPermission());
System.out.println(fileStatus.getLen());
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
for (BlockLocation bl : blockLocations) {
System.out.println("block-length:" + bl.getLength() + "--" + "block-offset:" + bl.getOffset());
String[] hosts = bl.getHosts();
for (String host : hosts) {
System.out.println(host);
}
}
System.out.println("--------------分割线--------------");
}
}
/**
* 通过流的方式上传文件到hdfs
*
* @param localPath 本地路径
* @param hdfsPath HDFS路径
* @param isOverWrite 是否覆盖
*/
public static void uploadStream(String localPath, String hdfsPath, boolean isOverWrite) throws Exception {
FSDataOutputStream outputStream = fs.create(new Path(hdfsPath), isOverWrite);
FileInputStream inputStream = new FileInputStream(localPath);
IOUtils.copyBytes(inputStream, outputStream, 4096);
}
/**
* 下载HDFS文件
* @param hdfsPath HDFS路径
* @param localPath 本地路径
*/
public static void downLoadStream(String hdfsPath, String localPath) throws IllegalArgumentException, IOException {
//先获取一个文件的输入流----针对hdfs上的
FSDataInputStream in = fs.open(new Path(hdfsPath));
//再构造一个文件的输出流----针对本地的
FileOutputStream out = new FileOutputStream(new File(localPath));
//再将输入流中数据传输到输出流
IOUtils.copyBytes(in, out, 4096);
}
/**
* 显示hdfs上文件的内容
* @param hdfsPath HDFS路径
*/
public static void catStream(String hdfsPath) throws IllegalArgumentException, IOException {
FSDataInputStream in = fs.open(new Path(hdfsPath));
IOUtils.copyBytes(in, System.out, 1024);
}
}
- 正确配置url后可以执行部分方法,如listAll()方法.
- 但是执行downloadFileToLocal()方法,会报错:HADOOP_HOME and hadoop.home.dir are unset.
- 这时需要配置windows的hadoop环境: 1.下载winutils, 配置HADOOP_HOME环境变量.
- 参考:https://blog.csdn.net/u013305864/article/details/97191344.
- 配置后,重启Idea,可成功执行.
代码测试
- 编写测试main方法,依次执行工具类中的方法
- 注意有的需要写到文件,有的需要写到文件夹
package com.data.test.HDFS;
import com.data.HDFS.HDFSUtil;
import java.io.IOException;
/**
* Created by zdf on 2022/4/12 15:53
*/
public class test {
public static void main(String[] args) throws Exception {
// HDFSUtil.listAll("/");
// HDFSUtil.addFileToHdfs("E:\\Temp\\autoData3.txt","/home/hadoop/zhangdongfei/data");
// HDFSUtil.catStream("/home/hadoop/zhangdongfei/data/autoData3.txt");
// HDFSUtil.uploadStream("E:\\Temp\\input.txt", "/home/hadoop/zhangdongfei/data/input.txt",false);
}
}
场景
很多有关HDFS的使用场景可以通过shell脚本的形式来完成任务,更加简洁并且易查看易修改.java调用HDFS考虑与其他组件的关联性更强,结合其他组件处理数据或者进行比较复杂的操作时适用性更强一些.