大数据—Hadoop—HDFS

概念

HDFS,全称:Hadoop Distributed File System,分布式文件存储系统,用于存储文件。通过目录树来定位文件;而且,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的文件在物理上是分块(block)存储的,在Hadoop2.X及以上的版本中,默认块的大小为128M(一次任务的最后一个块可以小于等于blocksize的1.1倍),块的大小可以通过参数(dfs.blocksize)来自定义。

特点

高容错
HDFS 采用数据的多副本方案,所以部分硬件的损坏不会导致全部数据的丢失。

高吞吐量
HDFS 设计的重点是支持高吞吐量的数据访问,而不是低延迟的数据访问。

大文件支持
HDFS 适合于大文件的存储,文档的大小应该是是 GB 到 TB 级别的。(HDFS中每个文件均按块存储,每个块的元数据存储在namenode的内存中,因此hadoop存储小文件会非常低效。因为大量的小文件会耗尽namenode中的大部分内存。但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多。例如,一个1MB的文件以大小为128MB的块存储,使用的是1MB的磁盘空间,而不是128MB。)
不过可以使用ARCHIVE命令采用Hadoop存档文件或HAR文件格式进行归档,不会减少文件存储大小,只会压缩NAMENODE 的空间使用。用法:

hadoop archive -archiveName  归档名称 -p 父目录 [-r <复制因子>]  原路径(可以多个)  目的路径

简单一致性模型
HDFS 更适合于一次写入多次读取 (write-once-read-many) 的访问模型。支持将内容追加到文件末尾,但不支持数据的随机访问,不能从文件任意位置新增数据。

跨平台移植性
HDFS 具有良好的跨平台移植性,这使得其他大数据计算框架都将其作为数据持久化存储的首选方案。

构架

HDFS集群包括,NameNodeDataNode以及Secondary Namenode

NameNode:负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息。
DataNode:负责管理用户的文件数据块,每一个数据块都可以在多个datanode上存储多个副本。
Secondary NameNode:用来监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS元数据的快照。
HDFS为主从结构,NameNode管理着一众DataNode,Secondary NameNode辅助 NameNode监控HDFS状态。

HDFS的数据流

HDFS数据写入

HDFS数据写入流程:

(1) 客户端向NameNode请求上传文件,NameNode检查目标文件是否存在,目录是否存在等等。
(2) NameNode应答客户端
(3) 按照blocksize将目标文件划分为不同Block,然后客户端请求第一个Block上传到哪几个DataNode服务器上。
(4) NameNode返回设置备份数(默认3个)个DataNode,分别为dn1,dn2,dn3。
(5) 客户端请求dn1上传块文件,dn1收到请求后会调用dn2,然后dn2调用dn3…,建立通信管道(pipeline)。
(6) dn1,dn2,dn3逐级应答客户端。
(7) 客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
(8) 当一个block传输完成之后,客户端再次请求NameNode上传第二个Block文件的DataNode服务器。(重复执行3-7步,直到任务完成)。
:如果在写的过程中某个DataNode发生错误,会采取以下几步:
1)关闭通信管道(pipeline)。
2)把产生错误的DataNode上当前在写但未完成的Block删掉。
3) Block剩下的部分被写到剩下的两个正常的DataNode中。
4) NameNode找到另外的DataNode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。
在这里插入图片描述

网络拓扑概念与机架感知副本放置策略:

在海量数据处理中,其主要限制因素是节点之间数据的传输速率——带宽很稀缺。所以将两个节点间的带宽作为节点间距离的衡量标准。

节点距离:两个节点到达最近的上级共同容器的距离总和。

例如,假设有数据中心d1机架r1中的节点n1。该节点可以表示为/d1/r1/n1。利用这种标记,这里给出四种距离描述。
Distance(/d1/r1/n1, /d1/r1/n1)=0(同一节点上的进程)
Distance(/d1/r1/n1, /d1/r1/n2)=2(同一机架上的不同节点)
Distance(/d1/r1/n1, /d1/r3/n2)=4(同一数据中心不同机架上的节点)
Distance(/d1/r1/n1, /d2/r4/n2)=6(不同数据中心的节点)

为保证数据安全性,数据存储在HDFS中基本会备份存储。考虑到数据安全性和数据带宽占用率之间的平衡,以默认3份备份为例,Hadoop默认副本节点选择为:
第一个副本在client所处的节点上。如果客户端在集群外,随机选一个;第二个副本和第一个副本位于相同机架,随机节点;第三个副本位于不同机架,随机节点。

HDFS数据读取

HDFS数据读取流程:
(1) 客户端向NameNoode请求下载目标文件。NameNode查找元数据,返回目标文件所在DataNode(就近原则,然后随机)服务器。
(2) 客户端向该DataNode请求读取目标文件。DataNode开始从服务器磁盘读取数据放入数据流(以packet为单位来做校验)。
(3) 客户端接受数据流,先放在本地缓存,然后写入目标目录。
在这里插入图片描述

NameNode & Secondary NameNode

NameNode & Secondary NameNode工作机制:

第一阶段:namenode启动
(1)第一次启动namenode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志(edits)和镜像文件(fsimage)到内存
(2)客户端对元数据进行增删改的请求
(3)namenode记录操作日志,更新滚动日志
(4)namenode在内存中对数据进行增删改查
第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问namenode是否需要checkpoint。直接带回namenode是否检查结果。
(2)Secondary NameNode请求执行checkpoint。
(3)namenode滚动正在写的edits日志
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint
(7)拷贝fsimage.chkpoint到namenode
(8)namenode将fsimage.chkpoint重新命名成fsimage
在这里插入图片描述

Fsimage(镜像文件)&edits(编辑日志):

namenode被格式化之后,将在hadoop-2.8.4/data/dfs/name/current目录中产生如下文件(注只能在NameNode所在的节点才能找到此文件):
edits_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION
文件解释:
(1)Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件idnode的序列化信息。
(2)Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。
(3)seen_txid文件保存的是一个数字,就是最后一个edits_的数字

每次Namenode启动的时候都会将fsimage文件读入内存,并从00001开始到seen_txid中记录的数字依次执行每个edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成Namenode启动的时候就将fsimage和edits文件进行了合并。

Secondary NameNode 的chkpoint(检查时间)参数设置:

(1)通常情况下,SecondaryNameNode每隔一小时执行一次。
[hdfs-default.xml]

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value> 
<description>检查间隔时间 ,秒为单位</description>
</property>

(2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。
[hdfs-default.xml]

<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
<description>操作动作次数</description>
</property>

<property>
  <name>dfs.namenode.checkpoint.check.period</name>
  <value>60</value>
<description> 1分钟检查一次操作次数,秒为单位</description>
</property>

利用Secondary NameNode恢复NameNode元数据

Secondary NameNode用来监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS元数据的快照。

在hadoop-2.8.4/data/dfs/namesecondary/current这个目录中查看Secondary NameNode目录结构:
edits_0000000000000000001-0000000000000000002
fsimage_0000000000000000002
fsimage_0000000000000000002.md5
VERSION

Secondary NameNode的namesecondary/current目录和主namenode的current目录的布局相同。

好处:在主namenode发生故障时(假设没有及时备份数据),可以从Secondary NameNode恢复数据。
方法一:将Secondary NameNode中数据拷贝到namenode存储数据的目录;
方法二:使用-importCheckpoint选项启动namenode守护进程,从而将Secondary NameNode中数据拷贝到namenode目录中。

1)案例实操(一):
模拟namenode故障,并采用方法一,恢复namenode数据

(1)kill -9 namenode进程

(2)删除namenode存储的数据(hadoop-2.8.4/data/dfs/name)

rm -rf /opt/module/hadoop-2.8.4/data/dfs/name/*

注:此时hadoop-daemon.sh stop namenode关闭NN,然后hadoop-daemon.sh start namenode重启NN,发现启动失败

(3)拷贝Secondary NameNode中数据到原namenode存储数据目录

cp -r hadoop-2.8.4/data/dfs/namesecondary/*  hadoop-2.8.4/data/dfs/name/

(4)重新启动namenode,启动成功

sbin/hadoop-daemon.sh start namenode

2)案例实操(二):
模拟namenode故障,并采用方法二,恢复namenode数据。

(0)修改hdfs-site.xml中的配置,value的单位是秒,默认3600,即1小时,仅配置一台即可

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>120</value>
</property>

<property>
  <name>dfs.namenode.name.dir</name>
  <value>/opt/module/hadoop-2.8.4/data/dfs/name</value>
</property>

(1)kill -9 namenode进程

(2)删除namenode存储的数据(/opt/module/hadoop-2.8.4/data/dfs/name)

rm -rf /opt/module/hadoop-2.8.4/data/dfs/name/*

(3)如果Secondary NameNode不和Namenode在一个主机节点上,需要将Secondary NameNode存储数据的目录拷贝到Namenode存储数据的平级目录。

pwd:/opt/module/hadoop-2.8.4/data/dfs
ls:data name namesecondary

(4)导入检查点数据(等待一会ctrl+c结束掉)

bin/hdfs namenode -importCheckpoint

(5)启动namenode

sbin/hadoop-daemon.sh start namenode

(6)如果提示文件锁了,可以删除in_use.lock

rm -rf /opt/module/hadoop-2.8.4/data/dfs/namesecondary/in_use.lock

NameNode多目录配置:

namenode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性。具体配置如下:
[hdfs-site.xml]

<property>
    <name>dfs.namenode.name.dir</name>
<value>file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2</value>
</property>
  1. 停止集群 删除data 和 logs rm -rf data/* logs/*
  2. hdfs namenode -format
  3. start-dfs.sh

实验总结:

思考1:如果在非Namenode节点、进行格式化(hdfs namenode -format)
是否和在NN节点上同样会生成name1和name2目录呢?

答:只要配置了以上得配置,在该节点下同样会生成name1和name2

具体解释:

格式化做了哪些事情?
在NameNode节点上,有两个最重要的路径,分别被用来存储元数据信息和操作日志,而这两个路径来自于配置文件,它们对应的属性分别是dfs.name.dir和dfs.name.edits.dir,同时,它们默认的路径均是/tmp/hadoop/dfs/name。格式化时,NameNode会清空两个目录下的所有文件,之后,格式化会在目录dfs.name.dir下创建文件hadoop.tmp.dir。这个配置会让dfs.name.dir和dfs.name.edits.dir会让两个目录的文件生成在一个目录里

思考2:非NN上如果生成了name1和name2,那么他和NN上生成得有没有差别?

答:有区别、NN节点上会产生新得edits_XXX,非NN不会fsimage会更新,而非NN不会,只会产生一个仅初始化得到fsimage,不会生成edits,更不会发生日志滚动。

DataNode

DataNode工作机制

1)一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度、块数据的校验和时间戳。
2)DataNode启动后向namenode注册,通过后,周期性(1小时)的向namenode上报所有的块信息。
3)心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。
4)集群运行中可以安全加入和退出一些机器
在这里插入图片描述
心跳机制补充:datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:
timeout = 2 * (dfs.namenode.heartbeat.recheck-interval) + 10 * dfs.heartbeat.interval。

而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。

需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。

<property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
</property>
<property>
    <name> dfs.heartbeat.interval </name>
    <value>3</value>
</property>

集群安全模式操作

概述

Namenode启动时,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的fsimage文件和一个空的编辑日志。此时,namenode开始监听datanode请求。但是此刻,namenode运行在安全模式,即namenode的文件系统对于客户端来说是只读的。

系统中的数据块的位置并不是由namenode维护的,而是以块列表的形式存储在datanode中。在系统的正常操作期间,namenode会在内存中保留所有块位置的映射信息。在安全模式下,各个datanode会向namenode发送最新的块列表信息,namenode了解到足够多的块位置信息之后,即可高效运行文件系统。

如果满足“最小副本条件”,namenode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以namenode不会进入安全模式。

基本语法

集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。
(1)bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态)
(2)bin/hdfs dfsadmin -safemode enter (功能描述:进入安全模式状态)
(3)bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)
(4)bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式状态)

safemode wait操作案例:

模拟等待安全模式:
1)先进入安全模式

bin/hdfs dfsadmin -safemode enter

2)执行下面的脚本
编辑一个脚本(注:必须已设置环境变量,要不就写绝对路径)

#!bin/bash
hdfs dfsadmin -safemode wait
hadoop fs -put /opt/BBB /

3)再打开一个窗口,执行

bin/hdfs dfsadmin -safemode leave

4)刚刚的命令成功执行

架构的稳定性

心跳机制和重新复制

每个 DataNode 定期向 NameNode 发送心跳消息,如果超过指定时间没有收到心跳消息,则将 DataNode 标记为死亡。NameNode 不会将任何新的 IO 请求转发给标记为死亡的 DataNode,也不会再使用这些 DataNode 上的数据。 由于数据不再可用,可能会导致某些块的复制因子小于其指定值,NameNode 会跟踪这些块,并在必要的时候进行重新复制。

数据的完整性

HDFS存储数据时会备份多份存放在不同的DataNode中以保证数据的稳定性。

由于存储设备故障等原因,存储在 DataNode 上的数据块也会发生损坏。为了避免读取到已经损坏的数据而导致错误,HDFS 提供了数据完整性校验机制来保证数据的完整性,具体操作如下:

当客户端创建 HDFS 文件时,它会计算文件的每个块的 校验和,并将 校验和 存储在同一 HDFS 命名空间下的单独的隐藏文件中。当客户端检索文件内容时,它会验证从每个 DataNode 接收的数据是否与存储在关联校验和文件中的 校验和 匹配。如果匹配失败,则证明数据已经损坏,此时客户端会选择从其他 DataNode 获取该块的其他可用副本。

元数据的磁盘故障

FsImage 和 EditLog 是 HDFS 的核心数据,这些数据的意外丢失可能会导致整个 HDFS 服务不可用。为了避免这个问题,可以配置 NameNode 使其支持 FsImage 和 EditLog 多副本同步,这样 FsImage 或 EditLog 的任何改变都会引起每个副本 FsImage 和 EditLog 的同步更新。也可以利用Secondary NameNode恢复NameNode元数据,具体操作见上。

支持快照

快照支持在特定时刻存储数据副本,在数据意外损坏时,可以通过回滚操作恢复到健康的数据状态。快照相当于对目录做一个备份。并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。
1)基本语法
(1)hdfs dfsadmin -allowSnapshot 路径 (功能描述:开启指定目录的快照功能)
(2)hdfs dfsadmin -disallowSnapshot 路径 (功能描述:禁用指定目录的快照功能,默认是禁用)
(3)hdfs dfs -createSnapshot 路径 (功能描述:对目录创建快照)
(4)hdfs dfs -createSnapshot 路径 名称 (功能描述:指定名称创建快照)
(5)hdfs dfs -renameSnapshot 路径 旧名称 新名称 (功能描述:重命名快照)
(6)hdfs lsSnapshottableDir (功能描述:列出当前用户所有已快照目录)
(7)hdfs snapshotDiff 路径1 路径2 (功能描述:比较两个快照目录的不同之处)
(8)hdfs dfs -deleteSnapshot (功能描述:删除快照)
2)案例实操

(1)开启/禁用指定目录的快照功能

hdfs dfsadmin -allowSnapshot /user/111/data		
hdfs dfsadmin -disallowSnapshot /user/111/data

(2)对目录创建快照

hdfs dfs -createSnapshot /user/111/data		// 对目录创建快照

用相同数据块

hdfs dfs -lsr /user/111/data/.snapshot/

(3)指定名称创建快照

hdfs dfs -createSnapshot /user/111/data miao170508

(4)重命名快照(注:快照是只读的,无法修改名)

hdfs dfs -renameSnapshot 快照的目录 老快照的名字 新快照的名字
hdfs dfs -renameSnapshot /plus/ plus plus	

注:路径只是你创建的名字/plus,不要带后边的/plus/.snapshot/,不然会出现
renameSnapshot: Modification on a read-only snapshot is disallowed

(5)列出当前用户所有可快照目录

hdfs lsSnapshottableDir	

(6)比较两个快照目录的不同之处

hdfs snapshotDiff 快照的目录 之前的快照名字  新快照的名字
hdfs snapshotDiff /user/111/data/  plus plus1	

(7)恢复快照

hdfs dfs -cp <path> <path>
  1. 自定义创建一个快照名:hdfs dfs -createSnapshot /HAHA1 miaomiao
  2. 展示原文件包含内容:Hadoop fs -ls /HAHA1
  3. 里面有五个文件、删除其中1~2个
  4. 回复快照:hdfs dfs -cp /HAHA1/.snapshot/miaomiao1 /miaomiao

(8)删除快照

hdfs dfs -deleteSnapshot <snapshotDir> <snapshotName>

回收站

1)启用回收站,默认值fs.trash.interval=0,0表示禁用回收站,可以设置删除文件的存活时间;默认值fs.trash.checkpoint.interval=0,检查回收站的间隔时间,要求fs.trash.checkpoint.interval<=fs.trash.interval,检查时间间隔小于回收站文件存活时间。

例:配置垃圾回收时间为1分钟。
[core-site.xml]

<property>
    <name>fs.trash.interval</name>
    <value>1</value>
</property>

2)查看回收站
回收站在集群中的;路径:/user/<用户名>/.Trash/….

3)修改访问垃圾回收站用户名称
进入垃圾回收站用户名称,默认是dr.who,修改为本用户
[core-site.xml]

<property>
  <name>hadoop.http.staticuser.user</name>
  <value>Xn</value>
</property>

4)通过程序删除的文件不会经过回收站,需要调用moveToTrash()才进入回收站

Trash trash = New Trash(conf);
trash.moveToTrash(path);

5)恢复回收站数据

hadoop fs -mv /user/<用户名>/.Trash/Current/user/itstar/input  /user/<用户名>/input

6)清空回收站

hdfs dfs -expunge

HDFS数据自动平衡脚本

在Hadoop中,包含一个start-balancer.sh脚本,通过运行这个工具,启动HDFS数据均衡服务。该工具可以做到热插拔,即无须重启计算机和 Hadoop 服务。Hadoop/bin目录下的start−balancer.sh脚本就是该任务的启动脚本。启动命令为:

bin/start-balancer.sh –threshold

影响Balancer的几个参数:

-threshold
默认设置:10
参数取值范围:0-100
参数含义:判断集群是否平衡的阈值。理论上,该参数设置的越小,整个集群就越平衡

dfs.balance.bandwidthPerSec
默认设置:1048576(1M/S)
参数含义:Balancer运行时允许占用的带宽

示例如下:

#启动数据均衡,默认阈值为 10%
$Hadoop_home/bin/start-balancer.sh

#启动数据均衡,阈值 5%
bin/start-balancer.sh –threshold 5

#停止数据均衡
$Hadoop_home/bin/stop-balancer.sh

在hdfs-site.xml文件中可以设置数据均衡占用的网络带宽限制

<property>
    <name>dfs.balance.bandwidthPerSec</name>
    <value>1048576</value>
    <description> Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second. </description>
    </property>

通过API操作HDFS

HDFS获取文件系统

  /**
     * 打印本地hadoop地址值
     * IO的方式写代码
     */
    @Test
public void intiHDFS() throws IOException {
        //注:import org.apache.hadoop.conf.Configuration;
        //1.创建配信信息对象 
        Configuration conf = new Configuration();

        //2.获取文件系统
        FileSystem fs = FileSystem.get(conf);

        //3.打印文件系统
        System.out.println(fs.toString());
    }

HDFS文件上传

   /**
     * 上传代码
     * 注意:如果上传的内容大于128MB,则是2块
     */
    @Test
    public void putFileToHDFS() throws Exception {
        //注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置信息对象
        Configuration conf = new Configuration();

        //2.设置部分参数
        conf.set("dfs.replication","2");

        //3.找到HDFS的地址
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //4.上传本地Windows文件的路径
        Path src = new Path("D:\\hadoop.rar");

        //5.要上传到HDFS的路径
        Path dst = new Path("hdfs://bigdata:9000/");

        //6.以拷贝的方式上传,从src -> dst
        fs.copyFromLocalFile(src,dst);

        //7.关闭
        fs.close();

        System.out.println("上传成功");
}

HDFS文件下载

    /**
     * hadoop fs -get /HDFS文件系统
     * @throws Exception
     */
    @Test
public void getFileFromHDFS() throws Exception {
        //注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置信息对象  Configuration:配置
        Configuration conf = new Configuration();

        //2.找到文件系统
        //final URI uri     :HDFS地址
        //final Configuration conf:配置信息
        // String user :Linux用户名
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //3.下载文件
        //boolean delSrc:是否将原文件删除
        //Path src :要下载的路径
        //Path dst :要下载到哪
        //boolean useRawLocalFileSystem :是否校验文件
        fs.copyToLocalFile(false,new Path("hdfs://bigdata:9000/README.txt"),
                new Path("F:\\date\\README.txt"),true);

        //4.关闭fs
        fs.close();
        System.out.println("下载成功");
    }

HDFS目录创建

 /**
     * hadoop fs -mkdir /xinshou
     */
    @Test
public void mkmdirHDFS() throws Exception {
        //注:import org.apache.hadoop.conf.Configuration;
        //1.创新配置信息对象
        Configuration configuration = new Configuration();

        //2.链接文件系统
        //final URI uri  地址
        //final Configuration conf  配置
        //String user   Linux用户
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), configuration, "root");

        //3.创建目录
        fs.mkdirs(new Path("hdfs://bigdata:9000/LuBenWeiNB "));

        //4.关闭
        fs.close();
        System.out.println("创建文件夹成功");
    }

HDFS文件夹删除

    /**
     * hadoop fs -rm -r /文件
     */
    @Test
public void deleteHDFS() throws Exception {
//注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置对象
        Configuration conf = new Configuration();

        //2.链接文件系统
        //final URI uri, final Configuration conf, String user
        //final URI uri  地址
        //final Configuration conf  配置
        //String user   Linux用户
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //3.删除文件
        //Path var1   : HDFS地址
        //boolean var2 : 是否递归删除
        fs.delete(new Path("hdfs://bigdata:9000/a"),false);

        //4.关闭
        fs.close();
        System.out.println("删除成功啦");
    }

HDFS文件名更改

	@Test
	public void renameAtHDFS() throws Exception{
//注:import org.apache.hadoop.conf.Configuration;
		// 1 创建配置信息对象
		Configuration configuration = new Configuration();
		
		FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"),configuration, "itstar");
		
		//2 重命名文件或文件夹
		fs.rename(new Path("hdfs://bigdata:9000/user/itstar/hello.txt"), new Path("hdfs://bigdata:9000/user/itstar/hellonihao.txt"));
	fs.close();
	}

HDFS文件详情查看

查看文件名称、权限、长度、块信息

  /**
     * 查看【文件】名称、权限等
     */
    @Test
public void readListFiles() throws Exception {
//注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置对象
        Configuration conf = new Configuration();

        //2.链接文件系统
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //3.迭代器
//List the statuses and block locations of the files in the given path. If the path is a directory, if recursive is false, returns files in the directory; if recursive is true, return files in the subtree rooted at the path. If the path is a file, return the file's status and block locations.

        RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

        //4.遍历迭代器
        while (listFiles.hasNext()){
            //一个一个出
            LocatedFileStatus fileStatus = listFiles.next();

            //名字
            System.out.println("文件名:" + fileStatus.getPath().getName());
            //块大小
            System.out.println("大小:" + fileStatus.getBlockSize());
            //权限
            System.out.println("权限:" + fileStatus.getPermission());
            System.out.println(fileStatus.getLen());


            BlockLocation[] locations = fileStatus.getBlockLocations();

            for (BlockLocation bl:locations){
                System.out.println("block-offset:" + bl.getOffset());
                String[] hosts = bl.getHosts();
                for (String host:hosts){
                    System.out.println(host);
                }
            }

            System.out.println("------------------华丽的分割线----------------");
        }

HDFS文件和文件夹判断

   /**
     * 判断是否是个文件还是目录,然后打印
     * @throws Exception
     */
    @Test
public void judge() throws Exception {
//注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置文件信息
        Configuration conf = new Configuration();

        //2.获取文件系统
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //3.遍历所有的文件
//List the statuses of the files/directories in the given path if the path is a directory.

        FileStatus[] liststatus = fs.listStatus(new Path("/"));
        for(FileStatus status :liststatus)
        {
            //判断是否是文件
            if (status.isFile()){
                System.out.println("文件:" + status.getPath().getName());
            } else {
                System.out.println("目录:" + status.getPath().getName());
            }
        }
    }

通过IO流操作HDFS

HDFS文件上传

    /**
     * IO流方式上传
     *
     * @throws URISyntaxException
     * @throws FileNotFoundException
     * @throws InterruptedException
     */
    @Test
public void putFileToHDFSIO() throws URISyntaxException, IOException, InterruptedException {
//注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置文件信息
        Configuration conf = new Configuration();

        //2.获取文件系统
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //3.创建输入流
        FileInputStream fis = new FileInputStream(new File("E:\\data\\Xn.txt"));

        //4.输出路径
        //注意:输出目录为 目录+文件名
        Path writePath = new Path("hdfs://bigdata:9000/Tmp/Xn.txt");
        FSDataOutputStream fos = fs.create(writePath);

        //5.流对接
        //InputStream in    输入
        //OutputStream out  输出
        //int buffSize      缓冲区
        //boolean close     是否关闭流
        try {
            IOUtils.copyBytes(fis,fos,4 * 1024,false);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            IOUtils.closeStream(fos);
            IOUtils.closeStream(fis);
fs.close();

            System.out.println("上传成功啦");
        }
    }

HDFS文件下载

	/**
     * IO读取HDFS到控制台
     *
     * @throws URISyntaxException
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
public void getFileToHDFSIO() throws URISyntaxException, IOException, InterruptedException {
//注:import org.apache.hadoop.conf.Configuration;
        //1.创建配置文件信息
        Configuration conf = new Configuration();

        //2.获取文件系统
        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata:9000"), conf, "root");

        //3.读取路径
        Path readPath = new Path("hdfs://bigdata:9000/Tmp/Xn.txt");

        //4.输入
        FSDataInputStream fis = fs.open(readPath);

        //5.输出到控制台
        //InputStream in    输入
        //OutputStream out  输出
        //int buffSize      缓冲区
        //boolean close     是否关闭流
        IOUtils.copyBytes(fis,System.out,4 * 1024 ,true);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值