一、HDFS简介(一)HDFS产生背景及定义1、产生背景
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS就是分布式文件管理系统中的一种。
2、定义
HDFS ( Hadoop Distributed File System ),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
(二)HDFS的优点1、存储数据较大:运行在HDFS的应用程序有较大的数据处理要求,或存储从GB到TB级的超大文件。
2、支持流式数据访问:HDFS放宽了可移植操作系统接口(POSIX)的要求,可以以流的形式访问文件系统中的数据。
3、支持多硬件平台:Hadoop可以运行在廉价、异构的商用硬件集群上,并且在HDFS设计时充分考虑了数据的可靠性、安全性及高可用性,以应对高发的节点故障问题。
4、数据一致性高:应用程序采用“一次写入,多次读取”的数据访问策略,支持追加,不支持多次修改,降低了造成数据不一致性的可能性。
5、有效预防硬件失效:通常,硬件异常比软件异常更加常见,对于具有上百台服务器的数据中心而言,硬件异常是常态,HDFS的设计要有效预防硬件异常,并具有自动恢复数据的能力。
6、支持移动计算:计算与存储采取就近的原则,从而降低网络负载,减少网络拥塞。
(三)HDFS的局限性HDFS在处理一些特定问题上也存在着一定的局限性,并不适用所有情况,主要表现在以下三个方面:
1、不适合低延迟的数据访问:因为HDFS是为了处理大型数据集任务,主要针对高数据吞吐设计的,会产生高时间延迟代价。
2、无法高效地存储大量小文件:为了快速响应文件请求,元数据存储在主节点的内存中,文件系统所能存储的文件总数受限于NameNode的内存容量。小文件数量过大,容易造成内存不足,导致系统错误。
3、不支持多用户写入以及任意修改文件:在HDFS中,一个文件同时只能被一个用户写入,而且写操作总是将数据添加在文件末尾,并不支持多个用户对同一文件的写操作,也不支持在文件的任意位置进行修改。
二、HDFS体系结构(一)HDFS组成架构 HDFS的存储策略是把大数据文件分块并存储在不同的计算机节点(Nodes),通过NameNode管理文件分块存储信息(即文件的元信息)。下图给出了HDFS的体系结构图。
HDFS采用了典型的Master/Slave系统架构,一个HDFS集群通常包含一个NameNode节点和若干个DataNodes节点。一个文件被分成了一个或者多个数据块,并存储在一组DataNode上,DataNode节点可分布在不同的机架。在NameNode的统一调度下,DataNode负责处理文件系统客户端的读/写请求,完成数据块的创建、删除和复制。
1、NameNode ( nn ):就是Master,它是一个主管、管理者。
(1)管理HDFS的名称空间;
(2)配置副本策略;
(3)管理数据块(Block )映射信息;
(4)处理客户端读写请求。
2、DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操作。
(1)存储实际的数据块;
(2)执行数据块的读/写操作。
3、Client:就是客户端。
(1)文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;
(2)与NameNode交互,获取文件的位置信息;
(3)与DataNode交互,读取或者写入数据;
(4)Client提供一些命令来管理HDFS,比如NameNode格式化;
(5)Client可以通过一些命令来访问HDFS,比如对HDFS增删查改操作;
4、Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
(1)辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode ;
(2)在紧急情况下,可辅助恢复NameNode。
5、Block:数据块,磁盘进行数据读/写的最小单元。
HDFS中的文件在物理上是分块存储( Block ),块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在Hadoop2.x版本中是128M,老版本中是64M。
HDFS作为一个分布式文件系统,使用抽象的数据块具有以下优势:
(1)通过集群扩展能力可以存储大于网络中任意一个磁盘容量的任意大小文件;
(2)使用抽象块而非整个文件作为存储单元,可简化存储子系统,固定的块大小可方便元数据和文件数据块内容的分开存储;
(3)便于数据备份和数据容错提高系统可用性。HDFS默认将文件块副本数设定为3份,分别存储在集群不同的节点上。当一个块损坏时,系统会通过NameNode获取元数据信息,在其他机器上读取一个副本并自动进行备份,以保证副本的数量维持在正常水平 。
(二)机架感知策略 大规模Hadoop集群节点分布在不同的机架上,同一机架上节点往往通过同一网络交换机接,在网络带宽方面比跨机架通信有较大优势;但若某一文件数据块同时存储在同一机架上,可能由于电力或网络故障,导致文件不可用。HDFS采用机架感知技术来改进数据的可靠性、可用性和网络带宽的利用率。
通过机架感知,NameNode可确定每个DataNode所属的机架ID,HDFS会把副本放在不同的机架上。如上图所示,第一个副本B1在本地机器,第二个副本B2在远端机架,第三个副本B3看之前的两个副本是否在同一机架,如果是则选择其他机架,否则选择和第一个副本B1相同机架的不同节点,第四个及以上,随机选择副本存放位置。HDFS系统的机架感知策略的优势是防止由于某个机架失效导致数据丢失,并允许读取数据时充分利用多个机架的带宽。HDFS会尽量让读取任务去读取离客户端最近的副本数据以减少整体带宽消耗,从而降低整体的带宽延时。
对于副本距离的计算公式,HDFS采用如下约定:
(1)Distance(Rack 1/D1 Rack1/D1)= 0 # 同一台服务器的距离为0
(2)Distance(Rack 1/D1 Rack1/D3)= 2 # 同机架不同服务器距离为2
(3)Distance(Rack 1/D1 Rack2/D1)= 4 # 不同机架服务器距离为4
其中,Rack1、Rack2表示机柜标识号,D1、D2、D3表示所在机柜中的DataNode节点主机的编号。即同一主机的两个数据块的距离为0;同一机架不同主机上的两个数据块的距离为2;不同机架主机上的数据块距离为4。
通过机架感知,处于工作状态的HDFS总是设法确保数据块的3个副本(或更多副本)中至少有2个在同一机架,至少有1个处在不同机架(至少处在两个机架上)。
(三)安全模式 安全模式是HDFS所处的一种特殊状态,在这种状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。NameNode主节点启动后,HDFS首先进入安全模式,DataNode在启动时会向NameNode汇报可用的数据块状态等。当整个系统达到安全标准时,HDFS自动离开安全模式。
离开安全模式的基本要求:副本数达到要求的数据块占系统总数据块的最小百分比(还需要满足其他条件)。默认为0.999f,也就是说符合最小副本数要求的数据块占比超过99.9%时,并且其他条件也满足才能离开安全模式。
NameNode退出安全模式状态,然后继续检测,确认有哪些数据块的副本没有达到指定数目,并复制这些数据块到其他DataNode上。
(四)文件安全性 为了保证文件的安全性,HDFS提供备份NameNode元数据和增加Secondary NameNode节点两种基本方案。
(1)备份NameNode上持久化存储的元数据文件,然后再同步地将其转存到其他文件系统中,一种通常的实现方式是将NameNode中的元数据转存到远程的网络文件共享系统NFS中。
(2)在系统中同步运行一个Secondary NameNode节点,作为二级NameNode去周期性地合并编辑日志中的命名空间镜像。Secondary NameNode的运行通常需要大量的CPU和内存去做合并操作,建议将其安装在与NameNode节点不同的其他单独的服务器上,它会存储合并后的命名空间镜像,并在NameNode宕机后作为替补使用,以便最大限度地减少文件的损失。由于Secondary NameNode的同步备份总会滞后于NameNode,依然存在数据损失的风险。
(五)元数据持久化HDFS元数据(描述文件)持久化由FSimage和Editlog两个文件组成,随着HDFS运行进行持续更新,元数据持久化的过程如图所示。
元数据持久化的过程:
首先,主用NameNode(即图中的Active NameNode)接收文件系统操作请求,生成EditLog,并回滚日志,向EditLog.new中记录日志;
第二步,备用NameNode(即图中的Standby NameNode)从主用NameNode上下载FSimage,并从共享存储中读取EditLog;
第三步,备用NameNode将日志和旧的元数据合并,生成新的元数据FSImage.ckpt;
第四步,备用NameNode将元数据上传到主用NameNode;
第五步,主用NameNode将上传的元数据进行回滚;
最后,循环第一步。
三、HDFS中的数据流 Java抽象类org.apache.hadoop.fs.FileSystem定义了Hadoop的一个文件系统接口。该类是一个抽象类,通过以下两个方法可以创建FileSystem实例:
代码语言:javascript复制public static FileSystem.get(Configuration conf) throws IOException
public static FileSystem.get(URI uri, Configuration conf) throws IOException这两个方法均要求传递一个Configuration的对象实例,Configuration对象可以理解为描述Hadoop集群配置信息的对象。创建一个Configuration对象后,可调用Configuration.get()获取系统配置键值对属性。用户在得到一个Configuration对象之后就可以利用该对象新建一个FileSystem对象。
Hadoop抽象文件系统主要提供的方法可以分为两部分:一部分用于处理文件和目录相关的事务; 另一部分用于读/写文件数据。
处理文件和目录主要是指创建文件/目录、删除文件/目录等操作;读/写数据文件主要是指读取/写入文件数据等操作。这些操作与Java的文件系统API类似,如FileSystem.mkdirs(Path f, FsPermission permission)方法在FileSystem对象所代表的文件系统中创建目录,Java.io.File.mkdirs()也是创建目录的方法。FileSystem.delete(Path f)方法用于删除文件或目录,Java.io.File.delete()方法也用于删除文件或目录。
(一)文件的读取客户端从HDFS中读取文件的流程如图下图所示。
(1)客户端通过 Distributed FileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据,找到文件块所在的 DataNode 地址。
(2)挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)。
(4)客户端以Packet 为单位接收,先在本地缓存,然后写入目标文件。
(二)文件的写入客户端在HDFS中写入一个新文件的数据流过程如下图所示。
(1)客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
(2)NameNode 返回是否可以上传。
(3)客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
(4)NameNode 返回 3 个 DataNode 节点,分别为 dn1、dn2、dn3。
(5)客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
(6)dn1、dn2、dn3 逐级应答客户端。
(7)客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 packet 会放入一个应答队列等待应答。
(8)当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。
(重复执行 3-7 步)。
如果在数据写入期间DataNode发送故障,HDFS就会执行以下操作:
① 首先关闭管道,任何在确认队列中的数据包都会被添加到数据队列的前端,以保证管道中失败的DataNode的数据包不会丢失。当前存放在正常工作的DataNode上的数据块会被制定一个新的标识,并和NameNode进行关联,以便故障DataNode在恢复后可以删除存储的部分数据块。
② 然后,管道会把失败的DataNode删除,文件会继续被写到另外两个DataNode中。
③ 最后,NameNode会注意到现在的数据块副本没有达到配置属性要求,会在另外的DataNode上重新安排创建一个副本,后续的数据块继续正常接收处理。
(三)一致性模型 文件系统的一致性模型描述了文件读/写的数据可见性。文件被创建之后,当前正在被写入的块,其他读取者是不可见的。不过,HDFS提供一个sync()方法来强制所有的缓存与数据节点同步。在sync()返回成功后,HDFS能保证文件中直至写入的最后的数据对所有读取者都是可见且一致的。
HDFS的文件一致性模型与具体设计应用程序的方法有关。如果不调用sync(),一旦客户端或系统发生故障,就可能失去一个块的数据。所以,用户应该在适当的地方调用sync(),例如,在写入一定的记录或字节之后。尽管sync()操作被设计为尽量减少HDFS负载,但仍有开销,用户可通过不同的sync()频率来衡量应用程序,最终在数据可靠性和吞吐量找到一个合适的平衡。
(四)数据完整性 I/O操作过程中难免会出现数据丢失或脏数据,数据传输的量越大,出错的机率越高。比较传输前后校验和是最为常见的错误校验方法,例如,CRC32循环冗余检查是一种数据传输检错功能,对数据进行多项式计算32位的校验和,并将得到的校验和附在数据的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
HDFS也通过计算出CRC32校验和的方式保证数据完整性。HDFS会在每次读写固定字节长度时就计算一次校验和。这个固定的字节长度可由io.bytes.per.checksum指定,默认是512字节。HDFS每次读的时候也再计算并比较校验和。DataNode在收到客户端的数据或者其他副本传过来的数据时会校验数据的校验和。
HDFS数据流中,客户端写入数据到HDFS时,在管道的最后一个DataNode会去检查这个校验和,如果发现错误,就会抛出ChecksumException异常到客户端。
客户端从DataNode读数据的时候也要检查校验和,而且每个DataNode还保存检查校验和的日志,客户端的每一次校验都会记录到日志中。
除了读写操作会检查校验和以外,DataNode通过DataBlockScanner进程定期校验存在在它上面的数据块,预防诸如位衰减引起硬件问题导致的数据错误。 如果客户端发现有数据块出错,主要进行以下步骤恢复数据块:
(1)客户端在抛出ChecksumException之前会把坏的数据块和该数据块所在的DataNode报告给NameNode;
(2)NameNode把这个数据块标记为已损坏,这样NameNode就不会把客户端指向这个数据块,也不会复制这个数据块到其他的DataNode;
(3)NameNode会把一个好的数据块复制到另外一个DataNode;
(4)NameNode把损坏的数据块删除掉。
四、HDFS的Shell操作(一)基本语法1、bin/hadoop fs 具体命令
2、bin/hdfs dfs 具体命令
dfs 是 fs 的实现类。
(二)命令大全代码语言:javascript复制[root@bigdata zhc]# hdfs dfs
Usage: hadoop fs [generic options]
[-appendToFile
[-cat [-ignoreCrc]
[-checksum
[-chgrp [-R] GROUP PATH...]
[-chmod [-R]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] [-l] [-d] [-t
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc]
[-count [-q] [-h] [-v] [-t [
[-cp [-f] [-p | -p[topax]] [-d]
[-createSnapshot
[-deleteSnapshot
[-df [-h] [
[-du [-s] [-h] [-v] [-x]
[-expunge]
[-find
[-get [-f] [-p] [-ignoreCrc] [-crc]
[-getfacl [-R]
[-getfattr [-R] {-n name | -d} [-e en]
[-getmerge [-nl] [-skip-empty-file]
[-head
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [
[-mkdir [-p]
[-moveFromLocal
[-moveToLocal
[-mv
[-put [-f] [-p] [-l] [-d]
[-renameSnapshot
[-rm [-f] [-r|-R] [-skipTrash] [-safely]
[-rmdir [--ignore-fail-on-non-empty]
[-setfacl [-R] [{-b|-k} {-m|-x
[-setfattr {-n name [-v value] | -x name}
[-setrep [-R] [-w]
[-stat [format]
[-tail [-f] [-s
[-test -[defsz]
[-text [-ignoreCrc]
[-touch [-a] [-m] [-t TIMESTAMP ] [-c]
[-touchz
[-truncate [-w]
[-usage [cmd ...]]
Generic options supported are:
-conf
-D
-fs
-jt
-files
-libjars
-archives
The general command line syntax is:
command [genericOptions] [commandOptions](三)常用命令操作(0)启动 Hadoop 集群(方便后续的测试)
代码语言:javascript复制[root@bigdata zhc]# start-dfs.sh
[root@bigdata zhc]# start-yarn.sh(1)-help:输出这个命令参数
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -help rm(2)-ls: 显示目录信息
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -ls /(3)-mkdir:在 HDFS 上创建目录
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -mkdir -p /sanguo/shuguo/(4)-moveFromLocal:从本地剪切粘贴到 HDFS
代码语言:javascript复制[root@bigdata zhc]# touch kongming.txt
[root@bigdata zhc]# hdfs dfs -moveFromLocal ./kongming.txt /sanguo/shuguo(5)-appendToFile:追加一个文件到已经存在的文件末尾
代码语言:javascript复制[root@bigdata zhc]# touch liubei.txt
[root@bigdata zhc]# vi liubei.txt
输入
san gu mao lu
[root@bigdata zhc]# hdfs dfs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt(6)-cat:显示文件内容
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -cat /sanguo/shuguo/kongming.txt(7)-chgrp 、-chmod、-chown:Linux 文件系统中的用法一样,修改文件所属权限
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -chmod 666 /sanguo/shuguo/kongming.txt
[root@bigdata zhc]# hdfs dfs -chown atguigu:atguigu /sanguo/shuguo/kongming.txt(8)-copyFromLocal:从本地文件系统中拷贝文件到 HDFS 路径去
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -copyFromLocal README.txt /(9)-copyToLocal:从 HDFS 拷贝到本地
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -copyToLocal /sanguo/shuguo/kongming.txt ./(10)-cp :从 HDFS 的一个路径拷贝到 HDFS 的另一个路径
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -cp /sanguo/shuguo/kongming.txt /zhuge.txt(11)-mv:在 HDFS 目录中移动文件
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -mv /zhuge.txt /sanguo/shuguo/(12)-get:等同于 copyToLocal,就是从 HDFS 下载文件到本地
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -get /sanguo/shuguo/kongming.txt ./(13)-getmerge:合并下载多个文件,比如 HDFS 的目录 /user/atguigu/test 下有多个文件:log.1,log.2,log.3,...
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -getmerge /user/atguigu/test/* ./zaiyiqi.txt(14)-put:等同于 copyFromLocal
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -put ./zaiyiqi.txt /user/atguigu/test/(15)-tail:显示一个文件的末尾
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -tail /sanguo/shuguo/kongming.txt(16)-rm:删除文件或文件夹
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -rm /user/atguigu/test/jinlian2.txt(17)-rmdir:删除空目录
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -mkdir /test
[root@bigdata zhc]# hdfs dfs -rmdir /test(18)-du 统计文件夹的大小信息
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -du -s -h /user/atguigu/test
2.7 K /user/atguigu/test
[root@bigdata zhc]# hdfs dfs -du -h /user/atguigu/test
1.3 K /user/atguigu/test/README.txt
15 /user/atguigu/test/jinlian.txt
1.4 K /user/atguigu/test/zaiyiqi.txt(19)-setrep:设置 HDFS 中文件的副本数量
代码语言:javascript复制[root@bigdata zhc]# hdfs dfs -setrep 10 /sanguo/shuguo/kongming.txt 这里设置的副本数只是记录在 NameNode 的元数据中,是否真的会有这么多副本,还得看 DataNode 的数量。因为目前只有 3 台设备,最多也就 3 个副本,只有节点数的增加到 10台时,副本数才能达到 10。
五、HDFS的Java API操作(一)HDFS 文件上传(测试参数优先级)1、编写源代码
代码语言:javascript复制@Test
public void testCopyFromLocalFile() throws IOException,InterruptedException,URISyntaxException {
// 1 获取文件系统
Configuration configuration = new Configuration();
configuration.set("dfs.replication", "2");
FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"),configuration,"atguigu");
// 2 上传文件
fs.copyFromLocalFile(new Path("e:/banzhang.txt"), new Path("/banzhang.txt"));
// 3 关闭资源
fs.close();
System.out.println("over");
}2、将 hdfs-site.xml 拷贝到项目的根目录下
代码语言:javascript复制
3、参数优先级
参数优先级排序:(1)客户端代码中设置的值 >(2)ClassPath 下的用户自定义配置文
件 >(3)然后是服务器的默认配置
(二)HDFS文件下载代码语言:javascript复制@Test
public void testCopyToLocalFile() throws IOException,InterruptedException,URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), configuration, "atguigu");
// 2 执行下载操作
// boolean delSrc 指是否将原文件删除
// Path src 指要下载的文件路径
// Path dst 指将文件下载到的路径
// boolean useRawLocalFileSystem 是否开启文件校验
fs.copyToLocalFile(false, new Path("/banzhang.txt"), new Path("e:/banhua.txt"), true);
// 3 关闭资源
fs.close();
}(三)HDFS文件夹删除代码语言:javascript复制@Test
public void testDelete() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), configuration, "atguigu");
// 2 执行删除
fs.delete(new Path("/0508/"), true);
// 3 关闭资源
fs.close();
}(四)HDFS文件名更改代码语言:javascript复制@Test
public void testRename() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), configuration, "atguigu");
// 2 修改文件名称
fs.rename(new Path("/banzhang.txt"), new Path("/banhua.txt"));
// 3 关闭资源
fs.close();
}(五)HDFS文件详情查看查看文件名称、权限、长度、块信息
代码语言:javascript复制@Test
public void testListFiles() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件系统
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), configuration, "atguigu");
// 2 获取文件详情
RemoteIterator
while(listFiles.hasNext()){
LocatedFileStatus status = listFiles.next();
// 输出详情
// 文件名称
System.out.println(status.getPath().getName());
// 长度
System.out.println(status.getLen());
// 权限
System.out.println(status.getPermission());
// 分组
System.out.println(status.getGroup());
// 获取存储的块信息
BlockLocation[] blockLocations = status.getBlockLocations();
for (BlockLocation blockLocation : blockLocations) {
// 获取块存储的主机节点
String[] hosts = blockLocation.getHosts();
for (String host : hosts) {
System.out.println(host);
}
}
System.out.println("-----------班长的分割线----------");
}
// 3 关闭资源
fs.close();
}(六)HDFS文件和文件夹判断代码语言:javascript复制@Test
public void testListStatus() throws IOException, InterruptedException, URISyntaxException{
// 1 获取文件配置信息
Configuration configuration = new Configuration();
FileSystem fs =FileSystem.get(newURI("hdfs://bigdata:9000"),configuration,"atguigu");
// 2 判断是文件还是文件夹
FileStatus[] listStatus = fs.listStatus(new Path("/"));
for (FileStatus fileStatus : listStatus) {
// 如果是文件
if (fileStatus.isFile()) {
System.out.println("f:"+fileStatus.getPath().getName());
}else {
System.out.println("d:"+fileStatus.getPath().getName());
}
}
// 3 关闭资源
fs.close();
}