Hadoop HDFS 实践(2)—— 使用 Java 编程操作 HDFS 文件

接着上一篇:Hadoop HDFS 实践(1)—— 安装 IDEA 并创建项目

本笔记主要内容如下:

怎么说

查看 HDFS 中的文件列表

在项目目录 ~/src/main/java 下创建一个类,命名为 Ls.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;

public class Ls {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; // HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");

// 方法1:直接获取
FileStatus[] listStatus = fs.listStatus(new Path("/"));
for (FileStatus file : listStatus) {
System.out.println("[" + (file.isFile() ? "file" : "dir") + "]" + file.getPath().getName());
}

// 方法2:使用迭代器,并递归获取所有子文件夹下的文件
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
while (listFiles.hasNext()) {
System.out.println("========================");
LocatedFileStatus fileStatus = listFiles.next();
System.out.println("块大小:" + fileStatus.getBlockSize());
System.out.println("所属:" + fileStatus.getOwner());
System.out.println("备份数:" + fileStatus.getReplication());
System.out.println("权限:" + fileStatus.getPermission());
System.out.println("名称:" + fileStatus.getPath().getName());
System.out.println("---------块信息---------");
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
for (BlockLocation b : blockLocations) {
System.out.println("块起始偏移量" + b.getOffset());
System.out.println("块长度" + b.getLength());
// 块所在的datanode节点
String[] datanodes = b.getHosts();
for (String dn : datanodes) {
System.out.println("DataNode:" + dn);
}
}
}
}
}

首先启动 Hadoop,运行

1
$ /opt/app/hadoop-2.9.2/sbin/start-all.sh

待 Hadoop 成功运行后,右键点击代码,选择 Run 'Ls.main()'

运行结果 (由于篇幅限制,此处省略部分输出结果):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[dir]hbase
========================
块大小:134217728
所属:root
备份数:1
权限:rw-r--r--
名称:state-00000000000000000006.log
---------块信息---------


......


......


========================
块大小:134217728
所属:root
备份数:1
权限:rw-r--r--
名称:hadoop%2C33452%2C1553933199568.1553944017981
---------块信息---------
块起始偏移量0
块长度83
DataNode:hadoop
========================
块大小:134217728
所属:root
备份数:1
权限:rw-r--r--
名称:hbase.version
---------块信息---------
块起始偏移量0
块长度7
DataNode:hadoop

Process finished with exit code 0

可以看出这些文件是由 HBase 创建的,推测是之前初始化 HBase 的时候自动生成。

错误处理

在初次运行时会出现如图所示报错,且不会有任何输出。

log4j错误

这是由于 log4j 没有配置日志记录的位置,需要配置 log4j.properties。

解决方法

src 文件夹下新建 resources 文件夹,并在里面新建文件 log4j.properties,在文件中输入以下内容

1
2
3
4
5
6
hadoop.root.logger = DEBUG, console
log4j.rootLogger = DEBUG, console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n

解决log4j:WARN

重新运行代码,会有正常结果输出。

在 HDFS 中创建新目录

在 HDFS 中创建目录 /mkdir/a/b

在项目目录 ~/src/main/java 下创建一个类,命名为 Mkdir.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Mkdir {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; // HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");
boolean mkdirs = fs.mkdirs(new Path("/mkdir/a/b"));
System.out.println("创建目录结果:" + mkdirs);
}
}

运行,输出结果:

1
创建目录结果:true

使用 hdfs 命令验证

1
$ hdfs dfs -ls /mkdir/a/b

mkdir/a/b

没有报不存在的错误,创建成功!

上传文件到 HDFS

在当前项目目录下新建测试文件,上传到 HDFS 中的 /mkdir

先在项目目录下创建文件 Hello_World.txt,写入内容:This is a test file.

注意要在项目目录下创建,而不能在 src 目录下创建

然后在 ~/src/main/java 里创建一个类,命名为 Put.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Put {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; //HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");
String localpath = "Hello_World.txt";
fs.copyFromLocalFile(new Path(localpath), new Path("/mkdir"));
fs.close();
}
}

运行。

使用 hdfs 命令验证

1
$ hdfs dfs -ls /mkdir

Hello_World.txt上传成功

可以看到文件已经成功上传!

从 HDFS 下载文件到本地

把 HDFS 中的 /mkdir/Hello_World.txt 下载到指定目录下

在项目目录 ~/src/main/java 下创建一个类,命名为 Get.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Get {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; //HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");
String localpath = "Hello_World_2.txt";
fs.copyToLocalFile(new Path("/mkdir/Hello_World.txt"), new Path(localpath));
}
}

运行。

完毕后可以看到在项目目录下多出文件 Hello_World_2.txt,打开后内容和之前填入的一致。

下载成功!

Hello_World_2.txt下载成功

从 HDFS 中删除文件

删除 HDFS 中的 /mkdir/Hello_World.txt 文件

在项目目录 ~/src/main/java 下创建一个类,命名为 Del.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Del {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; //HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");
boolean ret = fs.delete(new Path("/mkdir/Hello_World.txt"), true);
System.out.println("删除结果:" + ret);
}
}

运行,输出结果:

1
删除结果:true

使用 hdfs 命令验证

1
$ hdfs dfs -ls /mkdir

删除成功

可以看到文件成功被删除!

重命名 HDFS 中的文件或文件夹

把 HDFS 中的 /mkdir/a 重命名为 /mkdir/a_2

在项目目录 ~/src/main/java 下创建一个类,命名为 Rename.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Rename {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; //HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");
fs.rename(new Path("/mkdir/a"), new Path("/mkdir/a_2"));
}
}

运行

使用 hdfs 命令验证

1
$ hdfs dfs -ls /mkdir

重命名成功

重命名成功!

流方式读取文件部分内容

上传一个文本文件,然后使用流方式读取部分内容保存到当前项目目录

首先创建一个文件 New.txt,内容为:

1
qwerasdfzxcv123456

上传到 HDFS 根目录

1
$ hdfs dfs -put New.txt /

在项目目录 ~/src/main/java 下创建一个类,命名为 StreamGet.java,写入代码

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.FileOutputStream;
import java.net.URI;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class StreamGet {
public static void main(String[] args) throws Exception {
String uri = "hdfs://192.168.29.127:8020/"; //HDFS地址
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), config, "root");
FSDataInputStream inputStream = fs.open(new Path("/New.txt"));
inputStream.seek(5); //指定读取的开始位置,这里设置为5,即从's'开始
FileOutputStream outputStream = new FileOutputStream("New.txt.part2"); //新的文件名为New.txt.part2
IOUtils.copy(inputStream, outputStream);
}
}

运行

可以看到项目目录下多出 New.txt.part2 文件,打开可以看到文件内容。

流方式读取文件部分内容

全文完

Hadoop HDFS 实践(2)—— 使用 Java 编程操作 HDFS 文件

https://morooi.cn/2019/operatehadoop02/

作者

SJ Zhou

发布于

2019-03-30

更新于

2021-01-06

许可协议

评论