* HDFS的工作原理是答辩重点(块、元数据、主/从节点SecondaryNameNode,FsImage、EditImage、存取策略/规则、数据出错与恢复、读写过程)
集群和分布式概念:
集群就是逻辑上处理同一任务的机器集合,可以属于同一机房,也可分属不同的机房。分布式这个概念可以运行在某个集群里面,某个集群也可作为分布式概念的一个节点。一句话,就是:“分头做事”与“一堆人”的区别。
分布式文件系统的结构:
分布式文件系统在物理结构上是由计算机集群中的多个节点构成的,这些节点分为两类,一类叫“主节点”(Master Node)或者也被称为“名称结点”(NameNode),另一类叫“从节点”(Slave Node)或者也被称为“数据节点”(DataNode)。
HDFS是存储数据的地方,就像电脑的硬盘一样,文件都存储在这个上面,MapReduce是对数据进行处理计算的,它有个特点就是不管多大的数据只要给它时间它就能把数据跑完,但是时间可能不是很快,所以它叫数据的批处理。YARN是体现Hadoop平台概念的重要组件,有了它大数据生态体系的其它软件就能在hadoop上运行了,这样就能更好的利用HDFS大存储的优势和节省更多的资源,比如我们就不用再单独建一个spark的集群了,让它直接跑在现有的hadoop yarn上面就可以了
HDFS:分布式存储
HDFS优点:
HDFS缺点:大量小文件存储在hdfs上时,压缩成一个文件(网盘不允许文件修改:百度、360网盘,国内80%的网盘都是基于hadoop)
HDFS 采用Master/Slave的架构来存储数据,这种架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode。下面我们分别介绍这四个组成部分。
块:HDFS块默认大小为64MB
块(Block):HDFS的文件被分成块进行存储,块是文件存储处理的逻辑单元
在HDFS里,所有的文件在存储的时候,都是把文件切分成相同固定大小的数据块,每个块默认大小是64MB字节。当文件传过来之后,系统把它拆分成块进行存储,若文件大小不到64MB,则单独存成一个block,存储到不同节点上, 默认情况下每个block都有三个副本。从管理上看,块是整个文件存储、处理的逻辑单元。我们进行的文件备份、查找也都是按照块来处理的。
注意: Block大小和副本数通过Client端上传文件时设置,文件上传成功后副本数可以变更,Block Size不可变更。
HDFS块存储优势:
支持大规模文件存储:一个大规模文件可以被分拆成若干个文件块,不同的文件块可以被分发到不同的节点上。
简化系统设计:简化了存储管理、方便了元数据的管理。
适合数据备份:每个文件块都可以冗余存储到多个节点上,大大提高了系统的容错性和可用性。
节点:NameNode和DataNode
NameNode(名称节点)是管理节点,存放元数据:①文件与数据块的映射表 ②数据块与数据节点的映射表
NameNode是管理节点,主要存放元数据。元数据包括两个部分:一个是文件和数据块的映射表;另一个是数据块和数据节点的映射表。客户端如果有一个访问请求,那么他首先要向NameNode去读取元数据 ,NameNode会返回相关的信息,说明这个文件是存放在,哪一些节点上面,于是他再去向这些节点去读取数据块,获取到数据块之后再进行组装,拼装成之前想要的文件。这就是HDFS里的主节点NameNode。
名称节点运行期间EditLog不断变大的问题,靠SecondaryNameNode第二名称节点解决。
第二名称节点是HDFS架构中的一个组成部分,它是用来保存名称节点中对HDFS 元数据信息的备份,并减少名称节点重启的时间。SecondaryNameNode一般是单独运行在一台机器上。
在名称节点运行期间,HDFS的所有更新操作都是直接写到EditLog中,久而久之, EditLog文件将会变得很大
虽然这对名称节点运行时候是没有什么明显影响的,但是,当名称节点重启的时候,名称节点需要先将FsImage里面的所有内容映像到内存中,然后再一条一条地执行EditLog中的记录,当EditLog文件非常大的时候,会导致名称节点启动操作非常慢,而在这段时间内HDFS系统处于安全模式,一直无法对外提供写操作,影响了用户的使用。
SecondaryNameNode的工作情况:
DataNode(数据节点)是HDFS的工作节点,存放数据块:
数据节点是分布式文件系统HDFS的工作节点,负责数据的存储和读取,会根据客户端或者是名称节点的调度来进行数据的存储和检索,并且向名称节点定期发送自己所存储的块的列表;每个数据节点中的数据会被保存在各自节点的本地Linux文件系统中。
第二类节点是DataNode,DataNode是HDFS里的工作节点,它是用来存放真正数据块的。
如刚才介绍主节点的图所示,左边的机架1,有3个DataNode节点,右边的机加2,有两个DataNode节点。这些DataNode是存放真正数据块。在这里补充说明一下,Hadoop为了保证节点因电力、网络的原因导致宕机,在集群的管理上引入机架的概念,用物理位置来提升集群的容灾能力。
HDFS体系结构:
名称节点作为中心服务器,负责管理文件系统的命名空间及客户端对文件的访问。集群中的数据节点一般是一个节点运行一个数据节点进程,负责处理文件系统客户端的读/写请求,在名称节点的统一调度下进行数据块的创建、删除和复制等操作。每个数据节点的数据实际上是保存在本地Linux文件系统中的。
HDFS要实现以下目标:
HDFS的局限性:
HDFS是hadoop的分布式文件系统,它和现有的分布式文件系统有很多共同特点,但同时区别也很明显,在设计HDFS的时候, Doug Cutting主要考虑了5个方面的因素:
HDFS存储原理:冗余数据保存
作为一个分布式文件系统,为了保证系统的容错性和可用性,HDFS采用了多副本方式对数据进行冗余存储,通常一个数据块的多个副本会被分布到不同的数据节点上,如图所示,数据块1被分别存放到数据节点A和C上,数据块2被存放在数据节点A和B上。
优点:(1)加快数据传输速度(2)容易检查数据错误(3)保证数据可靠性
数据存放规则:
HDFS存储原理:数据读取
获取机架ID:HDFS提供了一个API可以确定一个数据节点所属的机架ID,客户端也可以调用API获取自己所属的机架ID。当客户端读取数据时,从名称节点获得数据块不同副本的存放位置列表,列表中包含了副本所在的数据节点,可以调用API来确定客户端和这些数据节点所属的机架ID,当发现某个数据块副本对应的机架ID和客户端对应的机架ID相同时,就优先选择该副本读取数据,如果没有发现,就随机选择一个副本读取数据。
HDFS具有较高的容错性,可以兼容廉价的硬件,它把硬件出错看作一种常态,而不是异常,并设计了相应的机制检测数据错误和进行自动恢复,主要包括以下几种情形:名称节点出错、数据节点出错和数据出错。
名称节点出错
名称节点保存了所有的元数据信息,其中,最核心的两大数据结构是FsImage和Editlog,如果这两个文件发生损坏,那么整个HDFS实例将失效。因此,HDFS设置了备份机制,把这些核心文件同步复制到备份服务器SecondaryNameNode上。当名称节点出错时,就可以根据备份服务器SecondaryNameNode中的FsImage和Editlog数据进行恢复。
数据节点出错
每个数据节点会定期向名称节点发送“心跳”信息,向名称节点报告自己的状态。当数据节点发生故障,或者网络发生断网时,名称节点就无法收到来自一些数据节点的心跳信息,这时,这些数据节点就会被标记为“宕机”,节点上面的所有数据都会被标记为“不可读”,名称节点不会再给它们发送任何I/O请求。
这时,有可能出现一种情形,即由于一些数据节点的不可用,会导致一些数据块的副本数量小于冗余因子,名称节点会定期检查这种情况,一旦发现某个数据块的副本数量小于冗余因子,就会启动数据冗余复制,为它生成新的副本。
HDFS和其它分布式文件系统的最大区别就是可以调整冗余数据的位置。
网络传输和磁盘错误等因素,都会造成数据错误。客户端在读取到数据后,会采用md5和sha1对数据块进行校验,以确定读取到正确的数据。
在文件被创建时,客户端就会对每一个文件块进行信息摘录,并把这些信息写入到同一个路径的隐藏文件里面。当客户端读取文件的时候,会先读取该信息文件,然后,利用该信息文件对每个读取的数据块进行校验,如果校验出错,客户端就会请求到另外一个数据节点读取该文件块,并且向名称节点报告这个文件块有错误,名称节点会定期检查并且重新复制这个块。
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
FSDataInputStream in = fs.open(new Path(uri));
FSDataOutputStream out = fs.create(new Path(uri));
注意:创建一个Configuration对象时,其构造方法会默认加载工程项目下两个配置文件,分别是hdfs-site.xml以及core-site.xml,这两个文件中会有访问HDFS所需的参数值,主要是fs.defaultFS,指定了HDFS的地址(比如hdfs://localhost:9000),有了这个地址客户端就可以通过这个地址访问HDFS了。
1.首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例。
2.DistributedFileSystem通过rpc获得文件的第一批block的locations,同一个block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。
3.前两步会返回一个FSDataInputStream对象,该对象会被封装DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode并连接。
4.数据从datanode源源不断的流向客户端。
5.如果第一块的数据读完了,就会关闭指向第一块的datanode连接,接着读取下一块。这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流。
6.如果第一批block都读完了, DFSInputStream就会去namenode拿下一批block的locations,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。
如果在读数据的时候, DFSInputStream和datanode的通讯发生异常,就会尝试正在读的block的排序第二近的datanode,并且会记录哪个datanode发生错误,剩余的blocks读的时候就会直接跳过该datanode。 DFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后DFSInputStream在其他的datanode上读该block的镜像。
该设计就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanode, namenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FSDataInputStream;
public class Chapter3 {
public static void main(String[] args) {
try {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path filename = new Path(“hdfs://localhost:9000/user/hadoop/test.txt");
FSDataInputStream is = fs.open(filename);
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String content = d.readLine(); //读取文件一行
System.out.println(content);
d.close(); //关闭文件
fs.close(); //关闭hdfs
} catch (Exception e) {
e.printStackTrace();
}
}
}
1.客户端通过调用DistributedFileSystem的create方法创建新文件。
2.DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件,创建前, namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过, namenode就会记录下新文件,否则就会抛出IO异常。
3.前两步结束后,会返回FSDataOutputStream的对象,与读文件的时候相似, FSDataOutputStream被封装成DFSOutputStream。DFSOutputStream可以协调namenode和datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小的packet,然后排成队列data quene。
4.DataStreamer会去处理接受data quene,它先询问namenode这个新的block最适合存储的在哪几个datanode里(比如重复数是3,那么就找到3个最适合的datanode),把他们排成一个pipeline。DataStreamer把packet按队列输出到管道的第一个datanode中,第一个datanode又把packet输出到第二个datanode中,以此类推。
5.DFSOutputStream还有一个对列叫ack quene,也是由packet组成,等待datanode的收到响应,当pipeline中的所有datanode都表示已经收到的时候,这时akc quene才会把对应的packet包移除掉。
如果在写的过程中某个datanode发生错误,会采取以下几步:
1) pipeline被关闭掉;
2)为了防止丢包ack quene里的packet会同步到data quene里;
3)把产生错误的datanode上当前在写但未完成的block删掉;
4)block剩下的部分被写到剩下的两个正常的datanode中;
5)namenode找到另外的datanode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。
6.客户端完成写数据后调用close方法关闭写入流。
7.DataStreamer把剩余得包都刷到pipeline里,然后等待ack信息,收到最后一个ack后,通知datanode把文件标视为已完成。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.Path;
public class Chapter3 {
public static void main(String[] args) {
try {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
byte[] buff = "Hello world".getBytes(); // 要写入的内容
String filename = " hdfs://localhost:9000/user/hadoop/test.txt "; //要写入的文件名
FSDataOutputStream os = fs.create(new Path(filename));
os.write(buff,0,buff.length);
System.out.println("Create:"+ filename);
} catch (Exception e) {
e.printStackTrace();
}
}
}
调用文件系统(FS)Shell命令应使用 hadoop fs
1.打开终端模拟器,切换到/apps/hadoop/sbin目录下,启动Hadoop
除了直接执行start-all.sh外,还可以分步启动start-dfs.sh和start-yarn.sh。
2.执行jps,检查一下Hadoop相关进程是否启动
3.在/目录下创建一个test1文件夹
4.在Hadoop中的test1文件夹中创建一个file.txt文件
5.查看根目录下所有文件
6.还可以使用ls -R的方式递归查看根下所有文件
7.将Hadoop根下test1目录中的file.txt文件,移动到根下并重命名为file2.txt
Hadoop中的mv用法同Linux中的一样,都可以起到移动文件和重命名的作用。
8.将Hadoop根下的file2.txt文件复制到test1目录下
9.在Linux本地/data目录下,创建一个data.txt文件,并向其中写入hello hadoop!
10.将Linux本地/data目录下的data.txt文件,上传到HDFS中的/test1目录下
11.查看Hadoop中/test1目录下的data.txt文件
12.除此之外还可以使用tail方法
tail方法是将文件尾部1K字节的内容输出。支持-f选项,行为和Unix中一致。
13.查看Hadoop中/test1目录下的data.txt文件大小
-du 后面可以不加-s,直接写目录表示查看该目录下所有文件大小
14.text方法可以将源文件输出为文本格式。允许的格式是zip和TextRecordInputStream。
15.stat方法可以返回指定路径的统计信息,有多个参数可选,当使用-stat选项但不指定format时候,只打印文件创建日期,相当于%y
下面列出了format的形式:
16.将Hadoop中/test1目录下的data.txt文件,下载到Linux本地/apps目录中
17.查看一下/apps目录下是否存在data.txt文件
18.使用chown方法,改变Hadoop中/test1目录中的data.txt文件拥有者为root,使用-R将使改变在目录结构下递归进行。
19.使用chmod方法,赋予Hadoop中/test1目录中的data.txt文件777权限
20.删除Hadoop根下的file2.txt文件
21.删除Hadoop根下的test1目录
22.当在Hadoop中设置了回收站功能时,删除的文件会保留在回收站中,可以使用expunge方法清空回收站。
在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结束。安全模式主要是为了系统启动的时候检查各个DataNode上数据块的有效性,同时根据策略必要的复制或者删除部分数据块。运行期通过命令也可以进入安全模式。在实践过程中,系统启动的时候去修改和删除文件也会有安全模式不允许修改的出错提示,只需要等待一会儿即可。
23.使用Shell命令执行Hadoop自带的WordCount
首先切换到/data目录下,使用vim编辑一个data.txt文件,内容为(hello world hello hadoop hello ipieuvre)
在HDFS的根下创建in目录,并将/data下的data.txt文件上传到HDFS中的in目录
执行hadoop jar命令,在hadoop的/apps/hadoop/share/hadoop/mapreduce路径下存在hadoop-mapreduce-examples-2.6.0-cdh5.4.5.jar包,我们执行其中的worldcount类,数据来源为HDFS的/in目录,数据输出到HDFS的/out目录
查看HDFS中的/out目录
24.进入Hadoop安全模式
25.退出Hadoop安全模式
view plain copy
26.切换到/apps/hadoop/sbin目录下,关闭Hadoop
view plain copy
HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础篇,为了实现本地与HDFS的文件传输,主要借助Eclipse开发环境,通过java编程实现了远程HDFS的文件创建,上传,下载,删除等。
其实对HDSF的文件操作主要有两种方式:命令行的方式和JavaAPI的方式。命令行的方式简单直接,但是必须要求本地机器也是在Linux系统中已经安装了hadoop,这对习惯用windows系统的用户来说不得不安装虚拟机,然后再在虚拟机上安装Linux系统,这是一种挑战。同时windows系统与虚拟机上安装的Linux系统进行文件传输也是要借助一些工具才可以实现。
为了实现以上所遇到诸如系统不一致,手动输入命令等的困扰,我们选择Java API的方式,有专门的API函数,可以在非Hadoop机器上实现访问,同时与系统无关(windows、Linux甚至XP系统也可以)。Hadoop中关于文件操作类基本上全部是在"org.apache.hadoop.fs"包中,Hadoop类库中最终面向用户提供的接口类是FileSystem,该类封装了几乎所有的文件操作,例如CopyToLocalFile、CopyFromLocalFile、mkdir及delete等。综上基本上可以得出操作文件的程序库框架:
operator( ) {
得到Configuration对象
得到FileSystem对象
进行文件操作
}
实现上述程序库框架中各个操作的具体步骤:
Java抽象类org.apache.hadoop.fs.FileSystem定义了hadoop的一个文件系统接口。该类是一个抽象类,通过以下两种静态工厂方法可以过去FileSystem实例:
public static FileSystem.get(Configuration conf) throws IOException
public static FileSystem.get(URI uri, Configuration conf) throws IOException
HDFS上的文件创建,上传,下载,删除等操作的具体方法实现:
(1)public boolean mkdirs(Path f) throws IOException
一次性新建所有目录(包括父目录), f是完整的目录路径。
(2)public FSOutputStream create(Path f) throws IOException
创建指定path对象的一个文件,返回一个用于写入数据的输出流
create()有多个重载版本,允许我们指定是否强制覆盖已有的文件、文件备份数量、写入文件缓冲区大小、文件块大小以及文件权限。
(3)public boolean copyFromLocal(Path src, Path dst) throws IOException
将本地文件拷贝到文件系统
(4)public boolean exists(Path f) throws IOException
检查文件或目录是否存在
(5)public boolean delete(Path f, Boolean recursive)
永久性删除指定的文件或目录,如果f是一个空目录或者文件,那么recursive的值就会被忽略。只有recursive=true时,一个非空目录及其内容才会被删除。
(6)FileStatus类封装了文件系统中文件和目录的元数据,包括文件长度、块大小、备份、修改时间、所有者以及权限信息。
本实验涉及到使用Java API对HDFS的一些基本操作。
- 创建类MakeDir.class,在HDFS的根目录下,创建名为hdfstest的目录。
- 创建类TouchFile.class,在HDFS的目录/hdfstest下,创建名为touchfile的文件。
- 创建类CopyFromLocalFile.class,将linux本地文件/data/mydata/sample_data,上传到HDFS文件系统的/hdfstest目录下。
- 创建类CopyToLocalFile.class,将HDFS文件系统上的文件/hdfstest/sample_data,下载到本地/data/mydata/copytolocal 。
- 创建类ListFiles.class,列出HDFS文件系统/hdfstest目录下,所有的文件,以及文件的权限、用户组、所属用户。
- 创建类IteratorListFiles.class,列出HDFS文件系统/根目录下,以及各级子目录下,所有文件以及文件的权限、用户组,所属用户。
- 了解FileSystem类下的方法,例如:判断文件是否存在、删除文件、重命名文件等。
- 创建类LocateFile.class,查看HDFS文件系统上,文件/hdfstest/sample_data的文件块信息。
- 创建类WriteFile.class,在HDFS上,创建/hdfstest/writefile文件,并在文件中写入内容“hello world hello data!”。
- 创建类PutMerge.class,将Linux本地文件夹/data/mydata/下的所有文件,上传到HDFS上并合并成一个文件/hdfstest/mergefile。
1.切换目录到/apps/hadoop/sbin下,启动hadoop。
view plain copy
在Linux本地创建/data/hadoop4目录。
view plain copy
2.切换到/data/hadoop4目录,用wget命令,从http://59.64.78.41:60000/allfiles/hadoop4/网址上下载依赖包hadoop2lib.tar.gz,并解压到当前目录。
view plain copy
3.新建JAVA项目,名为hadoop4。
4.在hadoop4项目下新建包,名为my.hdfs。
5.在hadoop4项目下创建目录,名为hadoop4lib,用于存放项目所需依赖包。
6.从/data/hadoop4/hadoop2lib目录下拷贝所有jar包到项目下的hadoop4lib目录。选中hadoop4lib里面的所有jar包,右键点击BuildPath=>Add to Build Path选项。
7.在my.hdfs包下,新建类MakeDir,程序功能是在HDFS的根目录下,创建名为hdfstest的目录。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class MakeDir {
public static void main(String[] args) throws IOException, URISyntaxException {
Configuration conf = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);
String newDir = "/hdfstest";
boolean result = hdfs.mkdirs(new Path(newDir));
if (result) {
System.out.println("Success!");
}else {
System.out.println("Failed!");
}
}
}
在Eclipse里执行,然后在HDFS上查看实验结果。
hadoop fs -ls /
8.在my.hdfs包下,新建类TouchFile,程序功能是在HDFS的目录/hdfstest下,创建名为touchfile的文件。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class TouchFile {
public static void main(String[] args) throws IOException, URISyntaxException {
Configuration configuration = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(new URI(hdfsPath), configuration);
String filePath = "/hdfstest/touchfile";
FSDataOutputStream create = hdfs.create(new Path(filePath));
System.out.println("Finish!");
}
}
在Eclipse里执行,然后在hdfs上查看实验结果。
hadoop fs -lsr /
9.在/data/hadoop4下使用vim打开sample_data文件,向sample_data文件中写入hello world。(使用vim编辑时,需输入a,开启输入模式)
cd /data/hadoop4
vim sample_data
hello world
在my.hdfs包下,创建类CopyFromLocalFile.class,程序功能是将本地linux操作系统上的文件/data/hadoop4/sample_data,上传到HDFS文件系统的/hdfstest目录下。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CopyFromLocalFile {
public static void main(String[] args) throws IOException, URISyntaxException {
Configuration conf = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);
String from_Linux = "/data/hadoop4/sample_data";
String to_HDFS = "/hdfstest/";
hdfs.copyFromLocalFile(new Path(from_Linux), new Path(to_HDFS));
System.out.println("Finish!");
}
}
在Eclipse里执行,然后在HDFS上查看实验结果。
hadoop fs -lsr /
10.在/data/hadoop4/下创建目录copytolocal。
mkdir /data/hadoop4/copytolocal
在my.hdfs包下,创建类CopyToLocalFile.class,程序功能是将HDFS文件系统上的文件/hdfstest/sample_data,下载到本地/data/hadoop4/copytolocal 。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CopyToLocalFile {
public static void main(String[] args) throws IOException, URISyntaxException {
Configuration conf = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);
String from_HDFS = "/hdfstest/sample_data";
String to_Linux = "/data/hadoop4/copytolocal";
hdfs.copyToLocalFile(false, new Path(from_HDFS), new Path(to_Linux));
System.out.println("Finish!");
}
}
在Eclipse里执行,然后在Linux本地/data/hadoop4上查看实验结果。
11.在my.hdfs包下,新建类ListFiles,程序功能是列出HDFS文件系统/hdfstest目录下,所有的文件,以及文件的权限、用户组、所属用户。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class ListFiles {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
String hdfspath = "hdfs://localhost:9000/";
FileSystem hdfs = FileSystem.get(URI.create(hdfspath), conf);
String watchHDFS = "/hdfstest";
FileStatus[] files = hdfs.listStatus(new Path(watchHDFS));
for (FileStatus file : files) {
System.out.println(file.getPermission() + " " + file.getOwner()
+ " " + file.getGroup() + " " + file.getPath());
}
}
}
在Eclipse里执行,然后在Eclipse的控制界面Console上查看实验结果。
12.在my.hdfs包下,新建类IteratorListFiles,程序功能是列出HDFS文件系统/根目录下,以及各级子目录下,所有文件以及文件的权限、用户组,所属用户。
package my.hdfs;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class IteratorListFiles {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
String hdfspath = "hdfs://localhost:9000/";
FileSystem hdfs = FileSystem.get(URI.create(hdfspath), conf);
String watchHDFS = "/";
iteratorListFile(hdfs, new Path(watchHDFS));
}
public static void iteratorListFile(FileSystem hdfs, Path path)
throws FileNotFoundException, IOException {
FileStatus[] files = hdfs.listStatus(path);
for (FileStatus file : files) {
if (file.isDirectory()) {
System.out.println(file.getPermission() + " " + file.getOwner()
+ " " + file.getGroup() + " " + file.getPath());
iteratorListFile(hdfs, file.getPath());
} else if (file.isFile()) {
System.out.println(file.getPermission() + " " + file.getOwner()
+ " " + file.getGroup() + " " + file.getPath());
}
}
}
}
在Eclipse里执行,然后在Eclipse的控制界面Console上查看实验结果。
13.文件是否存在、删除文件、重命名文件
了解FileSystem类下的方法,例如:判断文件是否存在、删除文件、重命名文件等。
FileSystem的方法exists、delete、rename。
14.在my.hdfs包下,新建类LocateFile,程序功能是查看HDFS文件系统上,文件/hdfstest/sample_data的文件块信息。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class LocateFile {
public static void main(String[] args) throws IOException, URISyntaxException {
Configuration conf = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);
Path file = new Path("/hdfstest/sample_data");
FileStatus fileStatus = hdfs.getFileStatus(file);
BlockLocation[] location = hdfs.getFileBlockLocations(fileStatus, 0, fileStatus.getLen());
for (BlockLocation block : location) {
String[] hosts = block.getHosts();
for (String host : hosts) {
System.out.println("block:" +block + " host:"+ host);
}
}
}
}
在Eclipse里执行,然后在Eclipse的控制界面Console上查看实验结果。
15.在my.hdfs包下,新建类WriteFile,程序功能是在HDFS上,创建/hdfstest/writefile文件并在文件中写入内容“hello world hello data!”。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class WriteFile {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(URI.create(hdfsPath), conf);
String filePath = "/hdfstest/writefile";
FSDataOutputStream create = hdfs.create(new Path(filePath));
System.out.println("Step 1 Finish!");
String sayHi = "hello world hello data!";
byte[] buff = sayHi.getBytes();
create.write(buff, 0, buff.length);
create.close();
System.out.println("Step 2 Finish!");
}
}
在Eclipse里执行,然后在HDFS上查看实验结果。
hadoop fs -lsr /hdfstest
hadoop fs -cat /hdfstest/writefile
16.首先切换到/data/hadoop4目录下,将该目录下的所有文件删除(此时要求/data/hadoop4中必须全是文件,不能有目录)。然后在该目录下新建两文件,分别命名为file1 ,file2。向file1和file2中,分别输入内容。
cd /data/hadoop4
rm -r /data/hadoop4/*
touch file1
touch file2
echo "hello file1" > file1
echo "hello file2" > file2
在my.hdfs包下,新建类PutMerge,程序功能是将Linux本地文件夹/data/hadoop4/下的所有文件,上传到HDFS上并合并成一个文件/hdfstest/mergefile。
package my.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class PutMerge {
public static void main(String[] args) throws IOException, URISyntaxException {
Configuration conf = new Configuration();
String hdfsPath = "hdfs://localhost:9000";
FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);
FileSystem local = FileSystem.getLocal(conf);
String from_LinuxDir = "/data/hadoop4/";
String to_HDFS = "/hdfstest/mergefile";
FileStatus[] inputFiles = local.listStatus(new Path(from_LinuxDir));
FSDataOutputStream out = hdfs.create(new Path(to_HDFS));
for (FileStatus file : inputFiles) {
FSDataInputStream in = local.open(file.getPath());
byte[] buffer = new byte[256];
int bytesRead = 0;
while ( (bytesRead = in.read(buffer) ) > 0) {
out.write(buffer, 0, bytesRead);
}
in.close();
}
System.out.println("Finish!");
}
}
在Eclipse里执行,然后在HDFS上查看实验结果。
hadoop fs -ls /hdfstest