在上节第三课中,我们介绍了Hadoop集群使用HDFS和MapReduce,我们在介绍HDFS时,都是直接运行hadoop命令来上传文件,这节课我们介绍在java环境调用和操作HDFS的文件管理功能。
我们知道,通过hadoop hive或spark等数据计算框架完成数据清洗后的数据是存储在HDFS上的,而爬虫和机器学习等程序在Python或java中容易实现,在Linux环境下编写Python或java程序没有那么便利,所以我们需要建立Python,Java与HDFS的读写通道。
1、建立Maven项目
首先,我们启动idea,我的版本是IntelliJ IDEA 2019.2.1 x64,点击左上角File=》New Project,弹出如下界面,我们在左侧选择Maven,然后默认jdk是1.8版本,点Next
我们输入项目信息,继续下一步
这一步我们选择maven版本,配置路径,继续下一步
好了,我们的项目已经建好并加载了,如下图,我们可以在右侧Maven界面先双击下install,让maven帮我们下载Maven项目引用的包,如下图所示
我们打开项目的pom.xml文件,加入引用hadoop相关的包,
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
加入引用后,我们Reimport一下,下载相关的包,下图可以看到,相关包已经下载
我们也可以在Maven面板看到依赖
2、添加hadoop配置文件
在我的第二节课,Hadoop集群安装与配置中,我们配置了5个文件,现在我们从服务器中复制出2个文件,core-site.xml和hdfs-site.xml,放到我们项目的资源目录
同时我们把resources目录设置为Resources Root
给大家看下core-site.xml,就是我第二节课的配置,没有改
3、编写测试程序
我们在java目录下,新建一个java类文件base_hdfs,加入下面的代码和引用
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.*;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class base_hdfs {
String hdfsURL = "hdfs://master105:9000";
FileSystem fs;
@Before
public void before() throws IOException, InterruptedException {
fs = FileSystem.get(URI.create(hdfsURL), new Configuration(), "root");
}
@Test
public void put() throws IOException, InterruptedException {
//设置配置文件
Configuration configuration = new Configuration();
// configuration.setInt("dfs.replication",1);//副本数
fs = FileSystem.get(URI.create(hdfsURL), configuration, "root");
fs.copyFromLocalFile(new Path("d:\\word0326.txt"),new Path("/mydata/test/out.txt"));
}
@Test
public void get() throws IOException, InterruptedException {
Configuration configuration = new Configuration();
FileSystem fileSystem = FileSystem.get(URI.create(hdfsURL), configuration, "root");
// fileSystem.copyFromLocalFile(new Path("E:\\a.txt"),new Path("/"));
fileSystem.copyToLocalFile(new Path("/jdk8"),
new Path("d:\\"));
fileSystem.close();
}
//修改名字
@Test
public void rename() throws IOException, InterruptedException {
//1、获取文件系统
FileSystem fileSystem = FileSystem.get(URI.create(hdfsURL), new Configuration(), "root");
fileSystem.rename(new Path("/mydata/test/out.txt"),new Path("/mydata/test/out0324.txt"));
fileSystem.close();
}
//删除
@Test
public void detele() throws IOException {
boolean delete = fs.delete(new Path("/mydata/test/out0324.txt"), true);
if (delete){
System.out.println("删除成功!");
}else{
System.out.println("删除失败!");
}
}
@Test
public void append() throws IOException {
FSDataOutputStream append = fs.append(new Path("/mydata/test/out.txt"), 1024);
// FSDataInputStream open = fs.open(new Path("/a.txt"));
final FileInputStream open = new FileInputStream("e:\\a.txt");
IOUtils.copyBytes(open,append,1024,true);
}
@Test
public void ls() throws IOException {
FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
for (FileStatus fileStatus : fileStatuses) {
boolean file = fileStatus.isFile();
//如果是文件
if (file){
System.out.println(fileStatus.getPath());
System.out.println(fileStatus.getLen());
}else{
System.out.println("这是一个文件夹");
System.out.println(fileStatus.getPath());
}
}
}
@Test
public void listFiles() throws IOException {
RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"), true);
while (files.hasNext()){
LocatedFileStatus file = files.next();
System.out.println("====================");
System.out.println(file.getPath());
BlockLocation[] blockLocations = file.getBlockLocations();
System.out.println("块信息:");
for (BlockLocation blockLocation : blockLocations) {
String[] hosts = blockLocation.getHosts();
System.out.print("块在:");
for (String host : hosts) {
System.out.print(host);
}
}
}
}
@After
public void after() throws IOException {
fs.close();
}
}
在上面的代码中,我们使用了junit进行单元测试,在测试方法前,我们定义了befor和after,
在一个JUnit4的单元测试用例执行顺序为:
@BeforeClass -> @Before -> @Test -> @After -> @AfterClass;
每一个测试方法的调用顺序为:
@Before -> @Test -> @After;
所以我们每执行一次测试方法,都会先调用befer打开HDFS连接,执行完后都会调用after关闭连接
接下来我们分别执行各个方法
1)上传文件put,我们在根目录指定了一个路径 /mydata/test/,我们刷新下http://master105:50070/explorer.html#/
可以看到文件已经上传
2)下载文件get
我们把之前测试上传的jdk8下载到本地d:\test下面,可以看到下载成功
3)修改文件名字rename,我们把刚才上传的文本out.txt改名为out0324.txt
执行后,我们刷新下文件管理页面,可以看到文件名已经修改
4)删除hdfs文件
我们执行删除刚才改名的文件,刷新管理页面,文件已经删除
5)追加文件内容append,我们先执行刚才的上传方法put,把out文件上传到/mydata/test目录,文本里面内容是
我们准备一个追加文件test.txt,内容是
我们执行append方法后,把服务器上的文件下载打开,可以看到文本已经加进去了
如果遇到下面的错误,不要慌,我们需要修改下配置文件
我们修改hdfs-site.xml文件,这里需要注意,我们既要修改集群里的文件,也要修改maven项目里的,我们加上配置
<property>
<name>dfs.client.block.write.replace-datanode-on-failure.policy</name>
<value>NEVER</value>
</property>
加完配置后,我们需要重启集群生效,然后在执行append方法就可以追加成功了
6)列出目录ls,我们这里是列出根目录 /,可以看到打印输出
7)列出文件信息listFiles,我们这里是列出根目录 / 下面文件所在服务器和块信息,可以看到打印输出
以上就是在java下操作HDFS的常用方法,还有更多方法可以去官网参考
总结
感谢能看到这里的朋友😉
本次的分享就到这里,猫头鹰数据致力于为大家分享技术干货😎
如果以上过程中出现了任何的纰漏错误,烦请大佬们指正😅
受益的朋友或对技术感兴趣的伙伴记得点赞关注支持一波🙏
也可以搜索关注我的微信公众号【猫头鹰数据分析】,留言交流🙏