大數據教程(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客戶端的角色。

        最後寄語,以上是博主本次文章的全部內容,如果大家覺得博主的文章還不錯,請點贊;如果您對博主其它服務器大數據技術或者博主本人感興趣,請關注博主博客,並且歡迎隨時跟博主溝通交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章