写在前面 本篇来学习如何访问HDFS文件系统,主要包括使用Shell和Java API这两种方式。
使用HDFS Shell方式 概述 HDFS提供了基于Shell的操作命令来管理HDFS上的数据,这些Shell命令和Linux系统上的命令非常相似,因此熟悉Linux的小伙伴可以快速对HDFS进行操作。
HDFS的基本命令格式为:
1 bin/hdfs dfs -cmd <args>
请注意在使用HDFS Shell之前,用户需要提前启动Hadoop。
一些常用的Shell命令 接下来学习一些HDFS Shell中常用的命令,如下所示:(1)列出HDFS指定路径下的文件目录 。其对应的命令格式如下所示:
举个例子,查看HDFS根目录下的文件:
1 2 3 4 5 6 [hadoop@master bin]$ hadoop fs -ls / Found 4 items -rw-r--r-- 1 hadoop supergroup 38 2020-06-20 22:08 /hello.txt drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:05 /helloworld drwx------ - hadoop supergroup 0 2020-06-20 22:11 /tmp drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:12 /wc_out
当然也可以使用-ls -R
命令来递归查看文件,这个命令不仅会打印出目录路径下的文件,还会打印出其子目录和子目录的文件。
举个例子,查看一下/data
目录下的所有文件:
1 2 [hadoop@master bin]$ hadoop fs -ls -R /data ls: `/data': No such file or directory
那是因为当前系统中不存在/data
目录。(2)在HDFS中创建目录。 其对应的命令格式如下所示:
举个例子,在HDFS的根目录下创建名为datatest的目录:
1 2 3 4 5 6 7 8 [hadoop@master bin]$ hadoop fs -mkdir /datatest [hadoop@master bin]$ hadoop fs -ls / Found 5 items drwxr-xr-x - root supergroup 0 2020-12-29 21:11 /datatest -rw-r--r-- 1 hadoop supergroup 38 2020-06-20 22:08 /hello.txt drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:05 /helloworld drwx------ - hadoop supergroup 0 2020-06-20 22:11 /tmp drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:12 /wc_out
当然,用户也可以使用-mkdir -p
参数来级联创建目录。
举个例子,开发者想在HDFS上创建/datatest/envy/input
目录,而envy目录之前是不存在的,因此就必须使用上面的级联创建目录:
1 2 3 4 [hadoop@master bin]$ hadoop fs -mkdir -p /datatest/envy/input [hadoop@master bin]$ hadoop fs -ls -R /datatest drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy/input
(3)上传文件至HDFS。 其对应的命令格式如下所示:
1 hadoop fs -put 源路径 目标存放路径
举个例子,将本地Linux文件系统目录/home/hadoop/
下的input.txt文件上传至Hadoop文件目录的/datatest
目录下:
1 2 3 4 5 6 7 8 [hadoop@master hadoop]$ hadoop fs -ls -R /datatest drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy/input [hadoop@master hadoop]$ hadoop fs -put /home/hadoop/input.txt /datatest [hadoop@master hadoop]$ hadoop fs -ls -R /datatest drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy/input -rw-r--r-- 1 root supergroup 13 2020-12-0621:27 /datatest/input.txt
(4)从HDFS上下载文件。 其对应的命令格式如下所示:
1 hadoop fs -get HDFS中文件路径 本地存放路径
举个例子,将前面上传的input.txt文件下载到本地用户的目录下,即/home/hadoop
目录:
1 2 3 [hadoop@master bin]$ hadoop fs -get /datatest/input.txt /home/hadoop/ [hadoop@master ~]$ ls input.txt
(5)查看HDFS上某个文件的内容。 其对应的命令格式如下所示:
1 2 3 hadoop fs -text HDFS上的文件存放路径 //或者 hadoop fs -cat HDFS上的文件存放路径
举个例子,查看我们之前上传的input.txt文件内的内容:
1 2 3 4 [hadoop@master ~]$ hadoop fs -text /datatest/input.txt hello,world! [hadoop@master ~]$ hadoop fs -cat /datatest/input.txt hello,world!
(6)统计HDFS上各目录下文件的大小。 其对应的命令格式如下所示:
举个例子,查看/datatest
目录下各个文件的大小:
bin]$ hadoop fs -du link 1 2 0 0 /datatest/envy 13 13 /datatest/input.txt
请注意上面统计的各目录下文件的大小时,使用的单位是字节 。(7)删除HDFS上某个文件或者目录。 其对应的命令格式如下所示:
1 2 3 hadoop fs -rm 文件存放路径 //或者 hadoop fs -rm -r 文件存放路径
请注意,在HDFS中删除文件和删除目录所使用的命令是不同的,-rm
参数表示删除指定的文件或者空目录;-rm -r
参数表示递归删除指定目录下的所有子目录和文件。
举个例子,删除之前上传的input.txt文件:
1 2 3 4 5 [hadoop@master bin]$ hadoop fs -rm /datatest/input.txt Deleted /datatest/input.txt [hadoop@master bin]$ hadoop fs -ls /datatest Found 1 items drwxr-xr-x - hadoop supergroup 0 2020-06-29 21:15 /datatest/envy
而删除/datatest
目录下的所有子目录和文件,则使用的命令为:
1 [hadoop@master bin]$ hadoop fs -rm -r /datatest
因此在生产环境中要避免使用-rm -r
参数,它会导致误删除操作。(8)使用help命令寻求帮助。 其对应的命令格式如下所示:
注意当开发者不知道某个命令的作用时,那么就可以使用help命令来寻求帮助,查询该命令的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [hadoop@master bin]$ hadoop fs -help ls -ls [-d] [-h] [-R] [<path> ...] : List the contents that match the specified file pattern. If path is not specified, the contents of /user/<currentUser> will be listed. Directory entries are of the form: permissions - userId groupId sizeOfDirectory(in bytes) modificationDate(yyyy-MM-dd HH:mm) directoryName and file entries are of the form: permissions numberOfReplicas userId groupId sizeOfFile(in bytes) modificationDate(yyyy-MM-dd HH:mm) fileName -d Directories are listed as plain files. -h Formats the sizes of files in a human-readable fashion rather than a number of bytes. -R Recursively list the contents of directories.
请注意,由于此处是对HDFS操作,因此上述命令中的hadoop fs
可以使用hdfs dfs
命令来进行代替。也就是说用户可以使用hadoop fs -ls
,也可以使用hdfs dfs -ls
命令来实现列出HDFS指定路径下的文件目录这一功能。
上面介绍的都是几个较为常用的Shell命令,因此需要熟练掌握,如果还想学习其他的Shell命令操作,可以点击 这里 进行学习:
使用Java API方式 概述 用户除了使用HDFS Shell方式来访问HDFS上的数据,还可以使用Java API来操作HDFS上的数据。由于在实际的大数据开发过程中都是以代码方式来开发的,因此对于Java API方式也必须掌握。
搭建开发环境 此处使用Maven来构建Java应用,因此需要使用Maven新建一个Java项目,名称为envy-hdfs,之后在其pom.xml依赖文件中新增如下依赖信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <hadoop.version>2.6.0</hadoop.version> </properties> <dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>${hadoop.version}</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>${hadoop.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> </dependencies>
由于我们在前面对HDFS的权限进行了设置,即在$HADOOP_HOME/etc/hadoop/hdfs-site.xml
中添加了如下配置,因此其他用户操作会提示没有权限:
1 2 3 4 <property> <name>dfs.permissions</name> <value>false</value> </property>
单元测试 在单元测试中,一般将初始化的操作放在setUp方法中,而将关闭资源的操作放在tearDown方法中来完成。出于上述考虑,笔者在测试HDFS时,将打开文件系统的操作放在setUp方法中,而将关闭文件系统的操作放在tearDown方法中。
在main包下的java包内新建com/envy/envyhdfs
包,之后在envyhdfs包内新建一个app包,并在app包内新建一个HDFSApp类,该类就是使用Java来操作HDFS的API:
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 package com.envy.envyhdfs.app; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.net.URI; /** * @描述:HDFS Java API操作 * @创建人: 余思 * @创建时间: 2020/06/29 */ public class HDFSApp { public static final String HDFS_PATH = "hdfs://master:9000"; Configuration configuration = null; FileSystem fileSystem = null; @Before public void setUp() throws Exception { System.out.println("*********HDFSApp.setUp()**********"); configuration = new Configuration(); fileSystem = FileSystem.get(new URI(HDFS_PATH),configuration); } @After public void tearDown() throws Exception { fileSystem = null; configuration = null; System.out.println("*********HDFSApp.tearDown()**********"); } }
使用Java API操作HDFS常用操作 接下来将在前面的HDFSApp中书写代码,通过使用Java API来操作HDFS,如下所示:
(1)创建目录。 先查询一下hdfs根目录下当前存有的目录信息:
1 2 3 4 5 [hadoop@master /]$ hadoop fs -ls / Found 3 items drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:05 /helloworld drwx------ - hadoop supergroup 0 2020-06-20 22:11 /tmp drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:12 /wc_out
接着在HDFSApp类中定义创建目录的方法mkdir:
1 2 3 4 5 @Test public void mkdir() throws IOException { System.out.println("********创建目录********"); fileSystem.mkdirs(new Path("/hdfsapi/test")); }
之后执行该方法,然后查询一下此时hdfs根目录下当前存有的目录信息:
1 2 3 4 5 6 [hadoop@master /]$ hadoop fs -ls / Found 4 items drwxr-xr-x - Administrator supergroup 0 2020-06-30 20:19 /hdfsapi drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:05 /helloworld drwx------ - hadoop supergroup 0 2020-06-20 22:11 /tmp drwxr-xr-x - hadoop supergroup 0 2020-06-20 22:12 /wc_out
可以看到多出了我们创建的/hdfsapi/test
目录。(2)创建文件。 在HDFSApp类中定义创建文件的方法create:
1 2 3 4 5 6 7 8 @Test public void create() throws Exception { System.out.println("********创建文件********"); FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test/hello.txt")) ; outputStream.write("hello,world".getBytes()); outputStream.flush(); outputStream.close(); }
之后执行该方法,然后查询一下此时hdfs中的/hdfsapi/test
目录下的信息:
1 2 3 [hadoop@master /]$ hadoop fs -ls -R /hdfsapi drwxr-xr-x - Administrator supergroup 0 2020-06-30 20:27 /hdfsapi/test -rw-r--r-- 3 Administrator supergroup 11 2020-06-30 20:27 /hdfsapi/test/hello.txt
可以看到此时/hdfsapi/test
目录下就出现了我们创建的hello.txt
文件。(3)重命名。 在HDFSApp类中定义重命名的方法rename:
1 2 3 4 5 6 7 @Test public void rename() throws Exception { System.out.println("********重命名********"); Path oldPath = new Path("/hdfsapi/test/hello.txt"); Path newPath = new Path("/hdfsapi/test/hello2.txt"); System.out.println(fileSystem.rename(oldPath,newPath)); }
之后执行该方法,可以看到该方法执行成功会输出true,然后查询一下此时hdfs中的/hdfsapi/test
目录下的信息:
1 2 3 [hadoop@master /]$ hadoop fs -ls -R /hdfsapi drwxr-xr-x - Administrator supergroup 0 2020-06-30 20:27 /hdfsapi/test -rw-r--r-- 3 Administrator supergroup 11 2020-06-30 20:27 /hdfsapi/test/hello2.txt
可以看到此时/hdfsapi/test
目录下的hello.txt
文件就已经修改为hello2.txt
文件。(4)上传本地文件到HDFS。 在HDFSApp类中定义上传本地文件到HDFS的方法copyFromLocalFile:
1 2 3 4 5 6 7 @Test public void copyFromLocalFile() throws Exception { System.out.println("********上传本地文件到HDFS********"); Path src = new Path("F:/Hadoop/hdfs/maven/envy-hdfs/src/main/resources/book.txt"); Path dist = new Path("/hdfsapi/test/"); fileSystem.copyFromLocalFile(src,dist); }
请注意,由于本地是Windows系统,因此这里的src源路径必须是Windows系统上的路径。之后执行该方法,然后查询一下此时hdfs中的/hdfsapi/test
目录下的信息:
1 2 3 4 [root@master sbin]# hadoop fs -ls -R /hdfsapi drwxr-xr-x - Administrator supergroup 0 2020-07-01 10:50 /hdfsapi/test -rw-r--r-- 3 Administrator supergroup 12 2020-07-01 10:50 /hdfsapi/test/book.txt -rw-r--r-- 3 Administrator supergroup 11 2020-06-30 20:27 /hdfsapi/test/hello2.txt
可以看到此时/hdfsapi/test
目录下就已经有了book.txt
文件。(5)查看某个目录下的所有文件。 在HDFSApp类中定义查看某个目录下的所有文件的方法listFiles:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void listFiles() throws Exception { System.out.println("********查看某个目录下的所有文件********"); FileStatus[] listStatus = fileSystem.listStatus(new Path("/hdfsapi/test")); for(FileStatus fileStatus:listStatus){ String isDir = fileStatus.isDirectory() ? "文件夹":"文件"; //文件夹或者文件 String permission = fileStatus.getPermission().toString(); //权限 short replication = fileStatus.getReplication(); //副本系数 long length = fileStatus.getLen(); //长度 String path = fileStatus.getPath().toString(); //路径 System.out.println(isDir+"\t"+permission+"\t"+replication+"\t"+length+"\t"+path); } }
先使用Hadoop Shell命令查看一下此时hdfs中的/hdfsapi/test
目录下的信息:
1 2 3 [root@master sbin]# hadoop fs -ls -R /hdfsapi/test -rw-r--r-- 3 Administrator supergroup 12 2020-07-01 10:50 /hdfsapi/test/book.txt -rw-r--r-- 3 Administrator supergroup 11 2020-06-30 20:27 /hdfsapi/test/hello2.txt
之后执行该方法,可以看到控制台输出如下信息:
1 2 3 4 ********查看某个目录下的所有文件******** 文件 rw-r--r-- 3 12 hdfs://master:9000/hdfsapi/test/book.txt 文件 rw-r--r-- 3 11 hdfs://master:9000/hdfsapi/test/hello2.txt *********HDFSApp.tearDown()**********
通过对比可以发现/hdfsapi/test
目录确实存在上述文件。(6)查看文件块信息。 在HDFSApp类中定义查看文件块信息的方法getFileBlockLocations:
1 2 3 4 5 6 7 8 9 10 11 @Test public void getFileBlockLocations() throws Exception { System.out.println("********查看文件块信息********"); FileStatus fileStatus = fileSystem.getFileStatus(new Path("/hdfsapi/test/book.txt")); BlockLocation[] blockLocations = fileSystem.getFileBlockLocations(fileStatus, 0, fileStatus.getLen()); for(BlockLocation blockLocation:blockLocations){ for(String host:blockLocation.getHosts()){ System.out.println(host); } } }
之后执行该方法,可以看到控制台输出如下信息:
1 2 3 ********查看文件块信息******** master *********HDFSApp.tearDown()**********
这样关于使用Shell和Java API这两种方式来访问HDFS文件系统的学习就到此为止,后续学习其他内容。