<dependencies>
<!--hadoop客户端-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.3.4</version>
</dependency>
<!--单元测试框架-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
在resources目录里创建log4j.properties文件
log4j.rootLogger=stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/hdfs.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
在HDFS Shell里利用hdfs dfs -touchz命令可以创建时间戳文件
创建net.hf.hdfs包,在包里创建CreateFileOnHDFS类
package net.hf.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.net.URI;
/**
* 功能:在HDFS上创建文件
* 作者:hf
* 日期:2022年11月25日
*/
public class CreateFileOnHDFS {
@Test
public void create1() throws Exception {
// 创建配置对象
Configuration conf = new Configuration();
// 定义统一资源标识符(uri: uniform resource identifier)
String uri = "hdfs://master:9000";
// 创建文件系统对象(基于HDFS的文件系统)
FileSystem fs = FileSystem.get(new URI(uri), conf);
// 创建路径对象(指向文件)
Path path = new Path(uri + "/ied01/hadoop.txt");
// 基于路径对象创建文件
boolean result = fs.createNewFile(path);
// 根据返回值判断文件是否创建成功
if (result) {
System.out.println("文件[" + path + "]创建成功!");
} else {
System.out.println("文件[" + path + "]创建失败!");
}
}
}
@Test
public void create2() throws Exception {
// 创建配置对象
Configuration conf = new Configuration();
// 定义统一资源标识符(uri:uniform resource identifier)
String uri = "hdfs://master:9000";
// 创建文件系统对象(基于HDFS的文件系统)
FileSystem fs = FileSystem.get(new URI(uri), conf);
// 创建路径对象
Path path = new Path(uri + "/ied01/hadoop.txt");
// 判断路径对象指向的文件是否存在
if (fs.exists(path)) {
// 提示用户文件已存在
System.out.println("文件[" + path + "]已经存在!");
} else {
// 基于路径对象创建文件
boolean result = fs.createNewFile(path);
// 根据返回值判断文件是否创建成功
if (result) {
System.out.println("文件[" + path + "]创建成功!");
} else {
System.out.println("文件[" + path + "]创建失败!");
}
}
}
类似于HDFS Shell里的hdfs dfs -put命令
在net.hf.hdfs包里创建WriteFileOnHDFS类
创建write1()方法
运行write1()测试方法,查看结果,抛出RemoteException异常,三个数据节点都在运行,但是无法写入数据
修改代码,设置数据节点主机名属性,如下图所示
package net.hf.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.net.URI;
/**
* 功能:写入HDFS文件
* 作者:hf
* 日期:2022年11月30日
*/
public class WriteFileOnHDFS {
@Test
public void write1() throws Exception {
//创建配置对象
Configuration conf = new Configuration();
// 设置数据节点主机名属性
conf.set("dfs.client.use.datanode.hostname", "true");
// 定义uri字符串
String uri = "hdfs://master:9000";
// 创建文件系统对象
FileSystem fs = FileSystem.get(new URI(uri), conf, "root");
// 创建路径对象(指向目录或文件)
Path path = new Path(uri + "/ied01/hello.txt");
// 创建文件系统数据字节输出流
FSDataOutputStream out = fs.create(path);
// 通过字节输出流向文件写数据
out.write("Hello Hadoop World".getBytes());
// 关闭输出流
out.close();
// 关闭文件系统对象
fs.close();
// 提示用户写入文件成功
System.out.println("文件[" + path + "]写入成功!");
}
}
@Test
public void write2() throws Exception {
// 创建配置对象
Configuration conf = new Configuration();
// 设置数据节点主机名属性
conf.set("dfs.client.use.datanode.hostname", "true");
// 定义统一资源标识符(uri: uniform resource identifier)
String uri = "hdfs://master:9000";
// 创建文件系统对象(基于HDFS的文件系统)
FileSystem fs = FileSystem.get(new URI(uri), conf, "root");
// 创建路径对象(指向文件)
Path path = new Path(uri + "/ied01/exam.txt");
// 创建文件系统数据字节输出流(出水管:数据从程序到文件)
FSDataOutputStream out = fs.create(path);
// 创建文件字符输入流对象(进水管:数据从文件到程序)
FileReader fr = new FileReader("test.txt");
// 创建缓冲字符输入流对象
BufferedReader br = new BufferedReader(fr);
// 定义行字符串变量
String nextLine = "";
// 通过循环遍历缓冲字符输入流
while ((nextLine = br.readLine()) != null) {
// 在控制台输出读取的行
System.out.println(nextLine);
// 通过文件系统数据字节输出流对象写入指定文件
out.write((nextLine + "\n").getBytes());
}
// 关闭缓冲字符输入流
br.close();
// 关闭文件字符输入流
fr.close();
// 关闭文件系统数据字节输出流
out.close();
// 提示用户写入文件成功
System.out.println("本地文件[test.txt]成功写入[" + path + "]!");
}
通过使用一个工具类IOUtils来更简单的处理
编写write2_()方法
运行write2_()测试方法,查看结果
查看/ied01/test.txt内容,文件是存在的,但是没有内容
@Test
public void write2_() throws Exception {
// 创建配置对象
Configuration conf = new Configuration();
// 设置数据节点主机名属性
conf.set("dfs.client.use.datanode.hostname", "true");
// 定义统一资源标识符(uri: uniform resource identifier)
String uri = "hdfs://master:9000";
// 创建文件系统对象(基于HDFS的文件系统)
FileSystem fs = FileSystem.get(new URI(uri), conf, "root");
// 创建路径对象(指向文件)
Path path = new Path(uri + "/ied01/test.txt");
// 创建文件系统数据字节输出流(出水管:数据从程序到文件)
FSDataOutputStream out = fs.create(path);
// 创建文件字节输入流(进水管:数据从文件到程序)
FileInputStream in = new FileInputStream("test.txt");
// 利用IOUtils类提供的字节拷贝方法在控制台显示文件内容
IOUtils.copyBytes(in, System.out, 1024, false);
// 再次读取文件数据到文件字节输入流
in = new FileInputStream("test.txt");
// 利用IOUtils类提供的字节拷贝方法来复制文件
IOUtils.copyBytes(in, out, conf);
// 关闭文件字节输入流
in.close();
// 关闭文件系统数据字节输出流
out.close();
// 提示用户写入文件成功
System.out.println("本地文件[test.txt]成功写入[" + path + "]!");
}
运行write2_()方法,查看结果
查看/ied01/test.txt文件
相当于Shell里的两个命令:hdfs dfs -cat和hdfs dfs -get
在net.hf.hdfs包里创建ReadFileOnHDFS类
准备读取hdfs://master:9000/ied01/test.txt文件
编写read1()方法
运行read1()测试方法,查看结果
可以使用IOUtils类来简化代码,创建read1_()测试方法
运行read1_()测试方法,查看结果
@Test
public void read2() throws Exception {
// 创建配置对象
Configuration conf = new Configuration();
// 设置数据节点主机名属性
conf.set("dfs.client.use.datanode.hostname", "true");
// 定义统一资源标识符(uri: uniform resource identifier)
String uri = "hdfs://master:9000";
// 创建文件系统对象(基于HDFS的文件系统)
FileSystem fs = FileSystem.get(new URI(uri), conf, "root");
// 创建路径对象(指向文件)
Path path = new Path(uri + "/ied01/test.txt");
// 创建文件系统数据字节输入流(进水管:数据从文件到程序)
FSDataInputStream in = fs.open(path);
// 创建文件字节输出流(出水管:数据从程序到文件)
FileOutputStream out = new FileOutputStream("download/exam.txt");
// 利用IOUtils工具类读取HDFS文件(靠输入流),写入本地文件(靠输出流)
IOUtils.copyBytes(in, out, conf);
// 关闭文件字节输出流
out.close();
// 关闭文件系统数据字节流输入流
in.close();
// 关闭文件系统
fs.close();
// 提示用户文件下载成功
System.out.println("文件[" + path + "]下载到本地文件[download/exam.txt]!");
}
相当于Shell里的hdfs dfs -mv命令
在net.hf.hdfs包里创建RenameDirOrFile类
编写renameDir()方法
运行renameDir()方法,查看结果
利用Hadoop WebUI界面查看
@Test
public void renameFile() throws Exception {
// 创建配置对象
Configuration conf = new Configuration();
// 设置数据节点主机名属性
conf.set("dfs.client.use.datanode.hostname", "true");
// 定义统一资源标识符(uri: uniform resource identifier)
String uri = "hdfs://master:9000";
// 创建文件系统对象(基于HDFS的文件系统)
FileSystem fs = FileSystem.get(new URI(uri), conf, "root");
// 创建源路径对象(指向文件)
Path sourcePath = new Path(uri + "/lzy01/hello.txt");
// 创建目标路径对象(指向文件)
Path destinationPath = new Path(uri + "/lzy01/hi.txt");
// 利用文件系统对象重命名文件
fs.rename(sourcePath, destinationPath);
// 关闭文件系统
fs.close();
// 提示用户文件更名成功
System.out.println("文件[" + sourcePath.getName() + "]更名为文件[" + destinationPath.getName() + "]!");
}
运行renameFile()测试方法,查看结果
利用Hadoop WebUI界面查看
在net.hf.hdfs包里创建ListHDFSFiles类
编写list1()方法
运行list1()测试方法,查看结果
上述文件状态对象封装的有关信息,可以通过相应的方法来获取,比如getPath()方法就可以获取路径信息,getLen()方法就可以获取文件长度信息……
编写list2()方法
运行list2()测试方法,查看结果
对照Hadoop WebUI上给出的文件长度信息
hadoop压缩包会分割成6个文件块
在net.hf.hdfs包里创建GetBlockLocations类
编写代码,获取文件块信息
运行程序,查看结果(切点位置,块大小,块存在位置)
在net.hf.hdfs包里创建MakeDirOnHDFS类
运行程序,查看结果
利用Hadoop WebUI界面查看
在net.hf.hdfs包里创建DirFileExistsOrNot类
编写dirExists()方法
运行程序,查看结果
修改代码,再测试
编写fileExists()方法
运行程序,查看结果
在net.hf.hdfs包里创建PathToFileOrDir类
运行程序,查看结果
类似于HDFS Shell里的hdfs dfs -rmdir和hdfs dfs -rm -r命令
在net.hf.hdfs包里创建DeleteFileOrDir类
编写deleteFile()方法
运行deleteFile()测试方法,查看结果
利用Hadoop WebUI界面查看
再运行deleteFile()测试方法,查看结果
可以在删除文件之前,判断文件是否存在,需要修改代码
此时运行deleteFile()测试方法,查看结果
编写deleteDir()方法
运行deleteDir()方法,查看结果
再运行deleteDir()方法,查看结果
进行三个层面的判断:判断是否存在、判断类型(目录或文件)、判断删除是否成功