前言html
咱們知道HDFS集羣中,全部的文件都是存放在DN的數據塊中的。那咱們該怎麼去查看數據塊的相關屬性的呢?這就是我今天分享的內容了java
1、HDFS中數據塊概述
1.一、HDFS集羣中數據塊存放位置
咱們知道hadoop集羣遵循的是主/從的架構,namenode不少時候都不做爲文件的讀寫操做,只負責任務的調度和掌握數據塊在哪些datanode的分佈,node
保存的是一些數據結構,是namespace或者相似索引之類的東西,真正的數據存儲和對數據的讀寫是發生在datanode裏的。apache
找到${HADOOP_HOME}/ect/hadoop/hdfs-site.xml文件,裏面有你本身定義的dfs.datanode.data.dir一項就是你數據存放的位置。api
此外咱們還能夠經過Web控制頁面(http://master:50070)的hdfs查看你所存放的全部數據文件,並且更加的清晰簡潔,包括文件的名稱,用了多少個數據塊存儲,數據塊的id,每一個數據塊寫入數據的大小。服務器
1.二、數據塊(data block)簡介
每一個磁盤都有默認的數據塊大小,這是磁盤進行數據讀/寫的最小單位,構建於單個磁盤之上的文件系統經過磁盤塊來管理該文件系統中的塊,該文件系統塊的大小能夠是磁盤塊的整數倍。網絡
HDFS一樣也有塊的概念,可是大得多,默認爲128MB(2.0之前是64MB)。與單一磁盤上的文件系統類似,HDFS上的文件也被劃分爲多個分塊,做爲獨立的存儲單元。數據結構
與其餘文件系統不一樣的是,HDFS中小於一個塊大小的文件不會佔據整個塊的空間。架構
1.三、對分佈式文件系統中的塊進行抽象會帶來不少好處
1)第一個明顯的好處是,一個文件的大小能夠大於網絡中任意一個磁盤的容量。文件的全部塊並不須要存儲在同一個磁盤上,所以他們能夠利用集羣上的任意一個磁盤進行存儲。
2)第二個好處是,使用塊抽象而非整個文件作爲存儲單元,大大簡化了存儲子系統的設計。簡化是全部系統的目標,可是這對於故障種類繁多的分佈式系統來講尤其重要。分佈式
將存儲子系統控制單元設置爲塊,可簡化存儲管理(因爲塊的大小是固定的,所以計算單個磁盤可以存儲多少個塊相對容易)。同時也消除了對元數據的顧慮(塊只是存儲數據的一部分---而文件的元數據,
如權限信息,並不須要與塊一同存儲,這樣一來,其餘的系統就能夠單獨管理這些元數據)。
3)塊很是適合用於數據備份進而提供數據容錯能力和可用性。將每一個塊複製到少數幾個獨立的機器上(默認爲3個),能夠確保在發生塊、磁盤或機器故障後數據不會丟失。
若是發現一個塊不可用,系統會從其餘地方讀取另外一個複本,而這個過程對用戶是透明的。
注意:HDFS中的文件都是一次性寫入的,而且嚴格要求在任什麼時候候只能有一個寫入者。
2、Java訪問HDFS中的數據塊
2.一、相關類和方法介紹
Hadoop關於HDFS中的數據塊相關類 org.apache.hadoop.hdfs.protocol包下。(不知道爲何在2.8的api中查詢不到,因此我只能經過IDEA去看源碼)
1)ExtendedBlock類(經過LocatedBlock的getBlock()方法獲取)
public String getBlockName() {}
public long getBlockId() {}
這裏主要是獲得數據塊的名字和id。
2)DatanodeInfo類
這裏列舉部分屬性
public String getIpAddr() {} public String getHostName() {}
3)LocatedBlock
public ExtendedBlock getBlock(){}
public long getBlockSize() {}
public long getStartOffset() {} //這個數據塊距離這個文件的偏移量
public DatanodeInfo[] getLocations() {} // 獲取當前的數據塊所在的DataNode的信息
2.二、編寫程序訪問
1)使用方法
在 HdfsDataInputStream中:獲取全部數據塊信息
2)ListBlocks_0010
import java.net.URI; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.client.HdfsDataInputStream; import org.apache.hadoop.hdfs.protocol.DatanodeInfo; import org.apache.hadoop.hdfs.protocol.ExtendedBlock; import org.apache.hadoop.hdfs.protocol.LocatedBlock; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; public class ListBlocks_0010 extends Configured implements Tool{ @Override public int run(String[] args) throws Exception{ Configuration conf=getConf(); String input=conf.get("input"); FileSystem fs= FileSystem.get( URI.create(input),conf); HdfsDataInputStream hdis= (HdfsDataInputStream) fs.open(new Path(input)); List<LocatedBlock> allBlocks= hdis.getAllBlocks(); for(LocatedBlock block:allBlocks){ ExtendedBlock eBlock= block.getBlock(); System.out.println("------------------------"); System.out.println( eBlock.getBlockId()); System.out.println( eBlock.getBlockName()); System.out.println( block.getBlockSize()); System.out.println( block.getStartOffset()); // 獲取當前的數據塊所在的DataNode的信息 DatanodeInfo[] locations= block.getLocations(); for(DatanodeInfo info:locations){ System.out.println( info.getIpAddr()); System.out.println( info.getHostName()); } } return 0; } public static void main(String[] args) throws Exception{ System.exit( ToolRunner.run( new ListBlocks_0010(),args)); } }
3)測試
在安裝了Hadoop客戶端的服務器中執行:
結果:
這裏解釋一下偏移量:
數據塊的偏移量是指一個數據塊距離一個文件開始的偏移位置(從上圖中能夠分析出來)
2、Java查看HDFS集羣文件系統
咱們怎麼去查看HDFS文件系統呢?咱們能夠經過FileSystem類中
1.一、相關類和方法
1)FileStatus類
FileStatus類封裝文件和目錄的文件系統元數據,包括文件長度,塊大小,複製,修改時間,全部權和許可信息。
FileSystem上的getFileStatus()方法提供了一種獲取FileStatus的方法對象爲單個文件或目錄。
getAccessTime() //上次訪問的時間 getOwner() //文件的全部者 getGroup() //文件的所屬者 getPath() //獲得文件的路徑 getPermission() //文件的權限 getReplication() //文件的備份數
2)FileSystem中的類
public FileStatus[] listStatus(Path f)throws IOException; public FileStatus[] listStatus(Path f, PathFilter filter)throws IOException; public FileStatus[] listStatus(Path[] files)throws IOException; public FileStatus[] listStatus(Path[] files, PathFilter filter)throws IOException;
2.二、編寫程序訪問
1)核心代碼
import java.io.IOException; import java.net.URI; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; public class ListFileStatus_0010 extends Configured implements Tool{ FileSystem fs; @Override public int run(String[] args) throws Exception{ Configuration conf=getConf(); String input=conf.get("input"); fs=FileSystem.get( URI.create(input),conf); FileStatus[] fileStatuses= fs.listStatus(new Path(input)); for(FileStatus status:fileStatuses){ process(status); } return 0; } public void process( FileStatus fileStatus) throws IOException{ if(fileStatus.isFile()){ System.out.println("--------------"); System.out.println( fileStatus.getAccessTime()); //上次訪問的時間 System.out.println( fileStatus.getOwner()); //文件的全部者 System.out.println( fileStatus.getGroup()); //文件的所屬者 System.out.println( fileStatus.getPath()); //獲得文件的路徑 System.out.println( fileStatus.getPermission()); //文件的權限 System.out.println( fileStatus.getReplication()); //文件的備份數 }else if(fileStatus.isDirectory()){ // 和Java的File不同的地方: // 當File對象所表明的是目錄的時候, // 能夠經過listFiles方法來獲取該目錄下的全部文件(有可能還包含目錄) // 在HDFS中,當FileStatus對象表明一個目錄的時候 // 沒有相應的方法來獲取該目錄下的全部文件 // 要經過FileSystem類來獲取該目錄下的文件 // path=fileStatus.getPath(); // FileStatus[] fileStstuses= // fs.listStatus(path); FileStatus[] fileStatuses= fs.listStatus(fileStatus.getPath()); for(FileStatus status:fileStatuses){ process(status); } } } public static void main(String[] args) throws Exception{ System.exit(ToolRunner.run(new ListFileStatus_0010(),args)); } }
2)測試
咱們先運行一個文件:
咱們運行一個目錄:有n多的文件,而且作了遞歸調用