文章目录
- HDFS读写流程
- API java实现
HDFS读写流程
1.客户端通过调用 DistributedFileSystem 的create方法,创建一个新的文件。
2.DistributedFileSystem 通过 RPC(远程过程调用)调用 NameNode,去创建一个没有blocks关联的新文件。创建前,NameNode 会做各种校验,比如文件是否存在, 客户端有无权限去创建等。如果校验通过,NameNode 就会记录下新文件,否则就会抛出IO异常。
3.前两步结束后会返回 FSDataOutputStream 的对象,和读文件的时候相似,FSDataOutputStream 被封装成 DFSOutputStream,DFSOutputStream 可以协调NameNode和 DataNode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列data queue。
4.DataStreamer 会去处理接受 data queue,它先问询 NameNode 这个新的 block 最适合存储的在哪几个DataNode里,比如重复数是3,那么就找到3个最适合的DataNode,把它们排成一个 pipeline。DataStreamer 把 packet 按队列输出到管道的第一个 DataNode 中,第一个 DataNode又把 packet 输出到第二个 DataNode 中,以此类推。
5.DFSOutputStream 还有一个队列叫 ack queue,也是由 packet 组成,等待DataNode的收到响应,当pipeline中的所有DataNode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。6.客户端完成写数据后,调用close方法关闭写入流。
7.DataStreamer 把剩余的包都刷到 pipeline 里,然后等待 ack 信息,收到最后一个ack 后,通知 DataNode 把文件标示为已完成。
- Client首先调用FileSystem对象的open方法,其实获取的是一个DistributedFileSystem的 实例。
- DistributedFileSystem通过RPC向NameNode获得文件的第一批block的locations,返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。
- 前两步会返回一个FSDataInputStream对象,该对象会被封装成 DFSInputStream 对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方 法,DFSInputStream就会找出离客户端最近的datanode并连接datanode。
- 数据从datanode源源不断的流向客户端。
- 如果第一个block块的数据读完了,就会关闭指向第一个block块的datanode连接, 接着读取下一个block块。这些操作对客户端来说是透明的,从客户端的角度来看只是 读一个持续不断的流。
- 如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的block块都读完,这时就会关闭掉所有的流。
API java实现
package hdfs;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.*;
import java.io.*;
public class aaa {
FileSystem fs = null;
Configuration conf =null;
public void init()throws Exception {
//Hadoop类库中提供的HDFS操作的核心API是FileSystem抽象类,该类提供了一系列方法来进行相关的操作
//FileSystem (不能生成对象)是一个通用的文件系统API,是一个抽象类,该类提供了一系列方法来进行相关的操作
//configuration对象是对文件系统中属性信息的封装,默认的属性来自hadoop配置文件core-site.xml中的配置
//进行文件操作的基本流程:1.创建configuration对象 2.利用fileSystem的静态get方法获取FileSystem实例 3.调用FileSystem的方法进行实际的文件操作
conf=new Configuration();
//conf.set("fs.defaultFS","hdfs://node01:8020");//设置本程序所访问的HDFS服务的地址,如果不通过代码进行设置,会默认取Hadoop安装环境下core-site.xml文件中配置的fs.defaultFS的属性值
fs=FileSystem.get(conf);//由于不能new,所以通过get静态方法来获取实例
}
//上传文件
public void upload() throws Exception{
fs.copyFromLocalFile(new Path("D:/text02.txt"), new Path("/"));
// 关闭
fs.close();
}
//使用流的方式上传文件
public void ioupload()throws IllegalArgumentException,IOException{
//true表示是否覆盖源文件
FSDataOutputStream out = fs.create(new Path("/text01.txt"),true);
FileInputStream in = new FileInputStream("D:/text02.txt");
//org.apabhe,commons.io下的IOUtils
IOUtils.copy(in,out);
}
//下载文件
public void download()throws Exception{
fs.copyToLocalFile(new Path("/text01.txt"),new Path("D:/text02.txt"));
fs.close();
}
//以流的方式下载文件
public void download2()throws Exception{
FSDataInputStream in = fs.open(new Path("/text01.txt"));
OutputStream out = new FileOutputStream("D:/text02.txt");
IOUtils.copy(in,out);
}
//创建目录
public void mkdir()throws IllegalArgumentException,IOException{
//可递归创建目录,返回值表示是否创建成功
boolean b = fs.mkdirs(new Path("/wj"));
System.out.println(b);
}
//删除目录或文件
public void delete ()throws IllegalArgumentException,IOException{
//true 表示递归删除,返回值代表是否删除成功
boolean b = fs.delete(new Path("/wj"));
System.out.println(b);
}
//打印指定路径下的文件信息(不含目录,可递归)
public void listFile()throws FileNotFoundException,IllegalArgumentException,IOException{
//true表示是否递归,返回的是迭代器对象
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"),true);
//fs.listFiles方法,返回LocatedFileStatus的迭代器,自带递归。但是它是继承于FileStatus的,而且构建函数是FileStatus的文件版,即LocaledFileStatus只能列出文件
while(listFiles.hasNext()){
LocatedFileStatus file = listFiles.next();
System.out.println("owner:"+file.getOwner());
System.out.println("filename:"+file.getPath().getName());
System.out.println("blocksize:"+file.getBlockSize());
System.out.println("replication"+file.getReplication());
System.out.println("permission"+file.getPermission());
BlockLocation[] blockLocations = file.getBlockLocations();
for (BlockLocation b : blockLocations){
System.out.println("块的起始偏移量"+b.getOffset());
System.out.println("块的长度"+b.getLength());
String[] hosts = b.getHosts();
for (String host : hosts){
System.out.println("块的所在服务器:"+host);
}
}
System.out.println("===================================");
}
}
//指定目录下的文件或目录信息(不可递归)
public void list()throws FileNotFoundException,IllegalArgumentException,IOException{
//返回的是数组,不能递归目录中的内容
//FileStatus对象封装了文件系统中文件和目录的元数据等信息
FileStatus[] listStatus = fs.listStatus(new Path("/"));//列出文件系统
for (FileStatus fs : listStatus){
System.out.println((fs.isFile()?"file:":"directory:")+fs.getPath().getName());
}
}
public static void main(String[] args)throws Exception{
// 选择本地运行,需要在本地安装hadoop环境
System.setProperty("hadoop.home.dir", "E:\\hadoop-2.6.5\\");
aaa HDFS =new aaa();
HDFS.init();
HDFS.upload();
//HDFS.ioupload();
//HDFS.mkdir();
//HDFS.delete();
//HDFS.listFile();
//HDFS.list();
}
}