本篇博客介绍使用Java API操作HDFS的方法。为本人的学习笔记。
学习参考视频教程:https://coding.imooc.com/class/301.html
方法
我们想要使用Java 来操作HDFS,就要先连接到HDFS文件系统,好在Hadoop 已经有了官方的jar包可以直接使用里面的类和方法。使用下面的定义的方法要首先创建一个maven项目,导入hadoop的依赖和junit的依赖。在pom.xml文件中的<dependencies>标签下增加下面的内容:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>hadoop.version</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
注意,要根据你hadoop的版本来确定配置文件中hadoop.version 的具体值。
在开发前,请确保正确安装了Hadoop,并且已经启动了HDFS,具体的操作可以查看我上一篇博客。需要注意的是,关于HDFS操作的相关端口要记得全部开放,所有的端口信息如下所示:
参数 | 描述 | 默认 | 配置文件 | 例子值 |
---|---|---|---|---|
fs.default.name.namenode | namenode RPC交互端口 | 8020 | core-site.xml | hdfs://master:8020 |
dfs.http.address | NameNode web管理端口 | 50070 | hdfs- site.xml | 0.0.0.0:50070 |
dfs.datanode.address | datanode 控制端口 | 50010 | hdfs -site.xml | 0.0.0.0:50010 |
dfs.datanode.ipc.address | datanode的RPC服务器地址和端口 | 50020 | hdfs-site.xml | 0.0.0.0:50020 |
dfs.datanode.http.address | datanode的HTTP服务器和端口 | 50075 | hdfs-site.xml | 0.0.0.0:50075 |
dfs.secondary.http.address | secondary NameNode web管理端口 | 50090 | hdfs-site.xml | 0.0.0.0:50090 |
如果在非生产环境下,比如只是为了学习,服务器是一个虚拟机,那么就可以偷个懒,直接把防火墙关闭了,所有端口就都开放了。也可以通过命令来开放这些端口,具体的操作方法见上一个博客。
示例代码
做好上面的步骤之后,就可以编写测试代码了,相关方法和注释见下面的代码示例:
package com.xjtu;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
public class JavaHadoopHDFSApiTest {
// 定义HDFS的连接地址(这里要改成你自己的配置)
public static String HDFS_PATH="hdfs://192.168.31.25:8020";
FileSystem fileSystem=null;
Configuration configuration=null;
// 指定连接的用户是谁(这里要改成你自己的用户)
String user="root";
/**
* 所有方法开始前都会运行这个方法,用于连接HDFS文件系统,获取FileSystem对象。
* @throws URISyntaxException
* @throws IOException
* @throws InterruptedException
*/
@Before
public void setUp() throws URISyntaxException, IOException, InterruptedException {
configuration=new Configuration();
// 设置副本数目为 1 (我在开发时没有设置集群,只有一个机器,副本数量设置为1就行)
configuration.set("dfs.replication","1");
fileSystem=FileSystem.get(new URI(HDFS_PATH),configuration,user);
}
/**
* 在HDFS上创建一个新的目录
* @throws IOException
*/
@Test
public void mkdirs() throws IOException {
String path="/qianqianjun/code";
Boolean result=fileSystem.mkdirs(new Path(path));
System.out.println(result);
}
/**
* 读取HDFS文件上的一个文本的内容
* @throws IOException
*/
@Test
public void text() throws IOException {
String path="/qianqianjun/code/a.cpp";
FSDataInputStream in=fileSystem.open(new Path(path));
IOUtils.copyBytes(in,System.out,1024);
}
/**
* 将HDFS上的一个文件重命名
* @throws IOException
*/
@Test
public void rename() throws IOException {
String oldpath="/love.cpp";
String newpath="/love.txt";
Boolean result=fileSystem.rename(new Path(oldpath),new Path(newpath));
if (result){
System.out.println("修改成功!");
}else{
System.out.println("修改失败!");
}
}
/**
* 将本地文件上传到HDFS
* @throws IOException
*/
@Test
public void copyFromLocalFile() throws IOException {
// src 是本地文件,dst是将本地文件上传到HDFS之后的位置
Path src=new Path("/home/qianqianjun/CODE/CPP/Clion/letcode/demo.cpp");
Path dst=new Path("/demo.cpp");
fileSystem.copyFromLocalFile(src,dst);
}
/**
* 带有进度条的大文件上传实现。
* @throws IOException
*/
@Test
public void copyFromLocalBigFile() throws IOException {
String fileName="/home/qianqianjun/下载/deepin.com.qq.im_9.1.8deepin0_i386.deb";
InputStream in=new BufferedInputStream(
new FileInputStream(new File(fileName))
);
FSDataOutputStream out=fileSystem.create(new Path("/software/qq.deb"),
new Progressable() {
@Override
public void progress() {
// 这里只实现了一个简单的功能,每上传4096字节,就输出一个“-”。
System.out.print("-");
}
});
IOUtils.copyBytes(in,out,4096);
}
/**
* 在HDFS上创建一个文件,并写入内容。
* @throws IOException
*/
@Test
public void create() throws IOException {
String path="/love.cpp";
FSDataOutputStream out=fileSystem.create(new Path(path));
out.writeUTF("hello world!\n");
out.writeUTF("best wishes\n");
// 将缓冲区中的内容全部写入文件。
out.flush();
out.close();
}
/**
* 将HDFS的文件下载到本地
* @throws IOException
*/
@Test
public void download() throws IOException {
Path src=new Path("/demo.cpp");
Path dst=new Path("/home/qianqianjun/桌面/download.cpp");
// src 是HDFS上文件的地址,dst是下载后的本地地址
fileSystem.copyToLocalFile(src,dst);
}
/**
* 列出对应HDFS目录的文件和文件夹
* @throws IOException
*/
@Test
public void listFiles() throws IOException {
Path path=new Path("/");
FileStatus[] fileStatuses=fileSystem.listStatus(path);
for(FileStatus file:fileStatuses){
String isDir=file.isDirectory()? "文件夹":"文件";
String permission=file.getPermission().toString();
short replication=file.getReplication();
long len=file.getLen();
String fullpath=file.getPath().toString();
System.out.printf("%s\t%s\t%d\t%d\t%s\n",isDir,permission,replication,len,fullpath);
}
}
/**
* 递归输出文件夹下面的文件。
* @throws IOException
*/
@Test
public void listFilesRecursive() throws IOException {
RemoteIterator<LocatedFileStatus> files=fileSystem.listFiles(new Path("/"),true);
while (files.hasNext()){
LocatedFileStatus file=files.next();
String isDir=file.isDirectory()? "文件夹":"文件";
String permission=file.getPermission().toString();
short replication=file.getReplication();
long len=file.getLen();
String fullpath=file.getPath().toString();
System.out.printf("%s\t%s\t%d\t%d\t%s\n",isDir,permission,replication,len,fullpath);
}
}
/**
* 获得HDFS上某个文件的块信息(开发中常用操作)
* @throws IOException
*/
@Test
public void getFileBlockLocations() throws IOException {
FileStatus fileStatus=fileSystem.getFileStatus(new Path("/software/qq.deb"));
BlockLocation[] blocks= fileSystem.getFileBlockLocations(fileStatus,0,fileStatus.getLen());
for(BlockLocation block:blocks){
for(String name:block.getNames()){
System.out.println(name+" : "+block.getOffset()+" : "+block.getLength());
}
}
}
/**
* 删除HDFS上的一个文件或者目录
* @throws IOException
*/
@Test
public void deleteHDFS() throws IOException {
Boolean result=fileSystem.delete(new Path("/software"),true);
System.out.println(result);
}
/***
* 定义执行完一个方法之后的操作。
*/
@After
public void endUp(){
configuration=null;
fileSystem=null;
}
}