HDFS读写数据(流程+操作)
一.文件上传(I/O流)
1)客户端通过DistributedFileSystem模块向namenode请求上传文件
namenode检查
(1)目标文件是否已经存在
(2)父目录是否存在
(3)是否有文件上传权限等
(4)如果检查没问题,则会发送允许上传的响应
fs.create(new Path("/input/hadoop-2.7.3.tar.gz"))
(1)创建这个目录
(2)需要计算文件大小
(3)返回给DFSclient对象
2)namenode返回是否可以上传
3)客户端请求第一个block上传到那几个datanode服务器上,addBlock()
- namenode返回3个datanode节点,分别为dn1,dn2,dn3;
5)客户端通过FSDataOutStream模块请求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步)
代码如下:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class HDFSio {
public static void main(String[] args)throws IOException,URISyntaxException,InterruptedException{
// readFileSeek1();
//readFileSeek2();
testput();
}
public static void testput() throws IOException {
//1.配置文件信息
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS", "hdfs://nn-master:9000");
//2.拿到文件系统对象
FileSystem fileSystem = FileSystem.get(configuration);
//3.找到目标地址的文件
FileInputStream inputStream = new FileInputStream(
new File("E:/hadoop-2.7.3.tar.gz"));
//4.明确本机主机上文件位置:FSDataOutputSream
FSDataOutputStream outputStream = fileSystem.create(new Path("/input/hadoop-2.7.3.tar.gz"));
//4.利用IOUtils将目标文件复制到本机对应的目录下即可
IOUtils.copyBytes(inputStream, outputStream, configuration);
//5.关闭资源
fileSystem.close();
}
二.定位文件读取
1)客户端向namenode发送文件下载请求
2)namenode进行一系列检查
文件是否存在,是否有权限等
如果这一系列的检查没有问题,这个时候开始查询自己的元数据库
返回数据对应的块以及块的存储位置给客户端
例如:
hadoop.tar.gz
blk_9988789:hadoop01 hadoop02
blk_9988790:hadoop02 hadoop03
3)客户端拿到数据块的存储信息,开始进行第一个块的下载
4)第一块下载完成后,进行CRT校验(循环冗余校验码常用于外存储器和计算机同步通信的数据校验)
5)开始进行第二个块的下载,重复步骤四,进行文件追加
6)当所有数据块下载成功后,客户端向namenode反馈
代码实现:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class HDFSio {
public static void main(String[] args)throws IOException,URISyntaxException,InterruptedException{
readFileSeek1();
readFileSeek2();
}
/**
在获取hdfs上的指定文件的第1块数据块
*/
public static void readFileSeek1() throws IOException,InterruptedException, URISyntaxException {
//1.获取文件系统
Configuration configuration=new Configuration();
FileSystem fs =FileSystem.get(new URI("hdfs://kepler:9000"),configuration,"root");
//2.获取输入流
FSDataInputStream fis=fs.open(new Path("/input/hadoop-2.7.3.tar.gz"));
//3.创建输出流
FileOutputStream fos=new FileOutputStream((new File("E:/hadoop-2.7.3.tar.gz.part1")));
//4.流的拷贝
byte[] buf=new byte[1024];
//注意1024*128=128KB;
//所以for循环了128KB次,每次循环从输入流中读取1024字节放buf中,总共读取的数据大小为128KB
for(int i=0;i<1024*128;i++){
fis.read(buf);
fos.write(buf);
}
//5.关闭资源
IOUtils.closeStream(fis);
IOUtils.closeStream(fos);
}
/**
在获取hdfs上的指定文件的第2块数据块
*/
public static void readFileSeek2() throws IOException,InterruptedException,URISyntaxException{
//1.获取文件系统
Configuration configuration=new Configuration();
FileSystem fs =FileSystem.get(new URI("hdfs://kepler:9000"),configuration,"root");
//2.获取输入流
FSDataInputStream fis=fs.open(new Path("/input/hadoop-2.7.3.tar.gz"));
//3.定位数据位置
fis.seek(1024*1024*128);
//4.创建输出流
FileOutputStream fos=new FileOutputStream(new File("E:/hadoop-2.7.3.tar.gz.part2"));
//5.流的对拷
IOUtils.copyBytes(fis,fos,configuration);
//6.关闭资源
IOUtils.closeStream(fis);
IOUtils.closeStream(fos);
}
}
合并文件