Hadoop(八)Java程序訪問HDFS集群中數據塊與查看文件系統


前言

  我們知道HDFS集群中,所有的文件都是存放在DN的數據塊中的。那我們該怎么去查看數據塊的相關屬性的呢?這就是我今天分享的內容了

一、HDFS中數據塊概述

1.1、HDFS集群中數據塊存放位置

  我們知道hadoop集群遵循的是主/從的架構,namenode很多時候都不作為文件的讀寫操作,只負責任務的調度和掌握數據塊在哪些datanode的分布,

  保存的是一些數據結構,是namespace或者類似索引之類的東西,真正的數據存儲和對數據的讀寫是發生在datanode里的。

  找到${HADOOP_HOME}/ect/hadoop/hdfs-site.xml文件,里面有你自己定義的dfs.datanode.data.dir一項就是你數據存放的位置。

  此外我們還可以通過Web控制頁面(http://master:50070)的hdfs查看你所存放的所有數據文件,而且更加的清晰簡潔,包括文件的名稱,用了多少個數據塊存儲,數據塊的id,每個數據塊寫入數據的大小。

    

1.2、數據塊(data block)簡介

  每個磁盤都有默認的數據塊大小,這是磁盤進行數據讀/寫的最小單位,構建於單個磁盤之上的文件系統通過磁盤塊來管理該文件系統中的塊,該文件系統塊的大小可以是磁盤塊的整數倍。

  HDFS同樣也有塊的概念,但是大得多,默認為128MB(2.0以前是64MB)。與單一磁盤上的文件系統相似,HDFS上的文件也被划分為多個分塊,作為獨立的存儲單元。

  與其他文件系統不同的是,HDFS中小於一個塊大小的文件不會占據整個塊的空間。

1.3、對分布式文件系統中的塊進行抽象會帶來很多好處

  1)第一個明顯的好處是,一個文件的大小可以大於網絡中任意一個磁盤的容量。文件的所有塊並不需要存儲在同一個磁盤上,因此他們可以利用集群上的任意一個磁盤進行存儲。
  2)第二個好處是,使用塊抽象而非整個文件做為存儲單元,大大簡化了存儲子系統的設計。簡化是所有系統的目標,但是這對於故障種類繁多的分布式系統來說尤為重要。

    將存儲子系統控制單元設置為塊,可簡化存儲管理(由於塊的大小是固定的,因此計算單個磁盤能夠存儲多少個塊相對容易)。同時也消除了對元數據的顧慮(塊只是存儲數據的一部分---而文件的元數據,

    如權限信息,並不需要與塊一同存儲,這樣一來,其他的系統就可以單獨管理這些元數據)。
  3)塊非常適合用於數據備份進而提供數據容錯能力和可用性。將每個塊復制到少數幾個獨立的機器上(默認為3個),可以確保在發生塊、磁盤或機器故障后數據不會丟失。

    如果發現一個塊不可用,系統會從其他地方讀取另一個復本,而這個過程對用戶是透明的

  注意:HDFS中的文件都是一次性寫入的,並且嚴格要求在任何時候只能有一個寫入者。

二、Java訪問HDFS中的數據塊

2.1、相關類和方法介紹 

  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.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客戶端的服務器中執行:

      

    結果:

      

    這里解釋一下偏移量:

      數據塊的偏移量是指一個數據塊距離一個文件開始的偏移位置(從上圖中可以分析出來)

       

二、Java查看HDFS集群文件系統

  我們怎么去查看HDFS文件系統呢?我們可以通過FileSystem類中

1.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.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多的文件,並且做了遞歸調用

      

      

 

 

喜歡就點個“推薦”哦!    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM