大数据教程(7.4)HDFS的java客户端API(流处理方式)

        博主上一篇博客分享了namenode和datanode的工作原理,本章节将继前面的HDFS的java客户端简单API后深度讲述HDFS流处理API。

        场景:博主前面的文章介绍过HDFS上存的大文件会成不同的块存储在不同的datanode节点上,对外提供统一的访问视图。但是,如果这个需要处理的文件整体特别大,我们在mapreduce程序中如果每次都全部下载到本地在执行那会非常耗时耗空间;那么,有没有一种好的方式,可以实现当前这个mapreduce任务处理的那个分片数据,就下载分片这一段的数据到本地进行处理。答案:HDFS流客户端API

        

package com.empire.hadoop.hadoop_demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;

import org.apache.commons.io.IOUtils;
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.junit.Before;
import org.junit.Test;


/**
 * 用流的方式来操作hdfs上的文件
 * 可以实现读取指定偏移量范围的数据
 * @author
 *
 */
public class HdfsStreamAccess {
	
	FileSystem fs = null;
	Configuration conf = null;
	
	@Before
	public void init() throws Exception{
		conf = new Configuration();
		conf.set("fs.defaultFS", "hdfs://master:9000");
		//客户端去操作hdfs时,是有一个用户身份的
		//默认情况下,hdfs客户端api会从jvm中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=hadoop
		//拿到一个文件系统操作的客户端实例对象
		/*fs = FileSystem.get(conf);*/
		System.setProperty("hadoop.home.dir", "E:\\\\hadoop-2.9.1");
		//可以直接传入 uri和用户身份
		//centos-aaron-h1为namenode的主机名或者域名
		fs = FileSystem.get(new URI("hdfs://centos-aaron-h1:9000"),conf,"hadoop"); //最后一个参数为用户名
	}
	/**
	 * 通过流的方式上传文件到hdfs
	 * @throws Exception
	 */
	@Test
	public void testUpload() throws Exception {
		
		FSDataOutputStream outputStream = fs.create(new Path("/angelababy.love"), true);
		FileInputStream inputStream = new FileInputStream("c:/angelababy.love");
		
		IOUtils.copy(inputStream, outputStream);
		
	}
	/**
	 * 通过流的方式获取hdfs上数据
	 * @throws Exception
	 */
	@Test
	public void testDownLoad() throws Exception {
		
		FSDataInputStream inputStream = fs.open(new Path("/angelababy.love"));		
		
		FileOutputStream outputStream = new FileOutputStream("d:/angelababy.love");
		
		IOUtils.copy(inputStream, outputStream);
		
	}
	@Test
	public void testRandomAccess() throws Exception{
		
		FSDataInputStream inputStream = fs.open(new Path("/angelababy.love"));
	
		inputStream.seek(12);
		
		FileOutputStream outputStream = new FileOutputStream("d:/angelababy.love.part2");
		
		IOUtils.copy(inputStream, outputStream);
		
	}
	/**
	 * 显示hdfs上文件的内容
	 * @throws IOException 
	 * @throws IllegalArgumentException 
	 */
	@Test
	public void testCat() throws IllegalArgumentException, IOException{
		
		FSDataInputStream in = fs.open(new Path("/angelababy.love"));
		
		IOUtils.copy(in, System.out);
		//hadoop的IOUtils更容易实现文件偏移分片处理
//		IOUtils.copyBytes(in, System.out, 1024);
	}
}

        前面的一些疑问总结:

hdfs dfsadmin -report 打印集群的状态,看到的内容相当准确
start-dfs.sh 如果namenode没关,也没关系

        HDFS listFiles()为何不直接反回List而是返回一个迭代器?因为如果listFiles参数传递的目录中包含几十亿个文件,那List直接放客户端内存,可能会让客户端吃不消;迭代器为何就行呢,迭代器其实不是个集合,它只是取数据的一种方式,它并不存数据,只是提供给一个方法,让你可以通过next(),nexthas()方法获取数据。

        mapreduce相对于HDFS来说,其实是一个HDFS客户端的角色。

        最后寄语,以上是博主本次文章的全部内容,如果大家觉得博主的文章还不错,请点赞;如果您对博主其它服务器大数据技术或者博主本人感兴趣,请关注博主博客,并且欢迎随时跟博主沟通交流。

猜你喜欢

转载自my.oschina.net/u/2371923/blog/2875256