1. 程式人生 > >Hadoop-2.4.1學習之FileSystem及實戰

Hadoop-2.4.1學習之FileSystem及實戰

      一提到hadoop檔案系統,通常想到的就是HDFS,即Hadoop Distributed File System,但除了HDFS外,hadoop還支援其它型別的檔案系統,比如Amazon S3、Swift檔案系統等,而這些檔案系統都擴充套件自抽象基礎類FileSystem,該類提供了豐富的方法用於對檔案系統進行操作,比如建立目錄、刪除檔案、重新命名等。無論使用的是HDFS還是Swift檔案系統,或者其它所支援的檔案系統,推薦在應用程式使用FileSystem物件引用實際的檔案系統,比如FileSystem local= FileSystem.getLocal(Configuration conf),該語句返回LocalFileSystem。FileSystem的類層次關係如下圖所示,其中將重點學習紅色標記的DistributedFileSystem,其它檔案系統只進行簡要的概述。


      FTPFileSystem,由Apache Commons Net提供的由FTP客戶端支援的檔案系統。S3FileSystem,由Amazon S3支援的基於block的檔案系統。NativeS3FileSystem,用於讀寫儲存在Amazon S3中檔案的檔案系統,與S3FileSystem不同的是,該實現將檔案按照原始格式儲存在S3,這樣其它S3工具可以讀取檔案。RawLocalFileSystem,原始的本地檔案系統,而繼承自ChecksumFileSystem的LocalFileSystem則為要計算校驗和的檔案系統。ChecksumFileSystem實現了一個客戶端掛載表,該類的規則和實現和ViewFs是相同的,詳細內容可以參考《

Hadoop-2.4.1學習之ViewFs》。HarFileSystem,Hadoop歸檔檔案系統,該歸檔檔案系統有形如_index*的索引檔案和形如part-*的內容檔案。HttpFSFileSystem允許使用者通過基於HTTP的HttpFSServer訪問HDFS。HftpFileSystem為基於HTTP訪問檔案系統的實現。WebHdfsFileSystem為HDFS在web上的檔案系統。SwiftNativeFileSystem為Swift(Openstack物件儲存)檔案系統的實現。最後一個也是最常用的檔案系統為DistributedFileSystem,該類實現了DFS系統,通過該類使用者程式碼與HDFS互動。

      在簡要概述了FileSystem及其子類後,回過頭再詳細學習一下該類的重要方法。由於該類為抽象類,故沒有辦法直接建立該類的物件,但該類提供了靜態方法用於建立物件,分別為:

方法

描述

get(Configuration conf)

根據conf獲取具體的檔案系統物件

get(URI uri, Configuration conf)

基於uri和conf建立檔案系統物件

get(URI uri, Configuration conf, String user)

基於uri,conf和user獲取檔案系統

getLocal(Configuration conf)

獲取本地檔案系統

newInstance(Configuration conf)

返回唯一的檔案系統物件,該方法總是返回新的物件

newInstance(URI uri, Configuration conf)

基於uri返回新的檔案系統物件

newInstance(URI uri, Configuration conf, String user)

基於uri,conf和user獲取檔案系統

newInstanceLocal(Configuration conf)

返回新的本地檔案系統物件

      同樣為獲取檔案系統物件的方法,get和newInstance有什麼不同呢?從描述可知,newInstance總是返回新的檔案系統物件,那get呢?要想了解其中的具體區別,最好的方法莫過於檢視原始碼了,首先檢視get(URI uri, Configuration conf)的原始碼:

public static FileSystem get(URI uri, Configuration conf) throws IOException {
    String scheme = uri.getScheme();
    String authority = uri.getAuthority();
    if (scheme == null && authority == null) {// use default FS
      //根據fs.defaultFS的值獲取檔案系統,若未設定該引數則根據file:///返回檔案系統
      return get(conf);
    }
    if (scheme != null && authority == null) {// no authority
      //根據fs.defaultFS的值建立URI,若未設定則使用file:///建立URI
      URI defaultUri = getDefaultUri(conf);
      if (scheme.equals(defaultUri.getScheme())    // if scheme matches default
          && defaultUri.getAuthority() != null) {  // & default has authority
        return get(defaultUri, conf);              // return default
      }
    }
    String disableCacheName = String.format("fs.%s.impl.disable.cache", scheme);
    if (conf.getBoolean(disableCacheName, false)) {
      //根據uri和conf建立FileSystem
      return createFileSystem(uri, conf);
}
//若未設定快取引數為true,則預設從CACHE中獲取檔案系統物件
    return CACHE.get(uri, conf);
  }

      從上面的程式碼可以得知,get方法不是每次都建立FileSystem物件,會從快取中獲取FileSystem物件,而newInstance方法則會每次都建立新物件。所以在使用該物件的API程式設計時,推薦使用get方法。在FileSystem中除了上述獲取物件的靜態方法外,還有一些其它方法,比如用於建立目錄的mkdirs,移動檔案的moveFromLocalFile和moveToLocalFile,複製檔案的copyToLocalFile和copyFromLocalFile,建立檔案的create等,這些方法都多個過載方法,可以根據需要選擇合適的方法。需要注意的是create方法並未建立檔案,而是返回了FSDataOutputStream物件,使用該物件就可以向檔案中寫入資料。

      除了FileSystem外,還有幾個類需要了解,分別為Path、FileStatus、FsStatus。其中FsStatus用於表示檔案系統的容量,已用和未用空間,方法分別為getCapacity、getUse和getRemaining。FileStatus用於獲取檔案系統的元資料,比如檔案大小,塊大小,檔案所有者,是否為目錄或者檔案等。Path表示檔案系統的一個檔案或者目錄,也就是Path物件對應了檔案系統的一個路徑,該路徑既可以是檔案也可以是目錄,如果以/開頭,那麼Path所表達的為絕對路徑。Path提供了一些用於判斷是否為根路徑、是否絕對路徑的方法,還有用於getName和toUri等方法。

      最後綜合上述知識,編寫一小段簡單的程式碼,該程式碼演示了部分方法的使用方式,更多內容可以參考官方API:

public class FileSystemTest {
	public static void main(String[] args) {
		Configuration conf = new Configuration();
		try {
			FileSystem local = FileSystem.getLocal(conf);		
			FileSystem hdfs = FileSystem.get(URI.create("hdfs://localhost:9000"),conf);
			FsStatus fsLocal = local.getStatus();
			FsStatus fsHdfs = hdfs.getStatus();
			System.out.println("Capacity: " + fsLocal.getCapacity()/1024/1024/1024 +"GB");
			System.out.println("Remaining :" + fsLocal.getRemaining()/1024/1024/1024 +"GB");
			System.out.println("Used: " + fsLocal.getUsed()/1024/1024/1024 +"GB");
			System.out.println();			
			System.out.println("Capacity: " + fsHdfs.getCapacity()/1024/1024/1024 +"GB");
			System.out.println("Remaining :" + fsHdfs.getRemaining()/1024/1024/1024 +"GB");
			System.out.println("Used: " + fsHdfs.getUsed()/1024/1024/1024 +"GB");
			
			Path hdfsPath = new Path("/user/hadoop/");
			lsFile(hdfsPath,hdfs);			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void lsFile(Path path,FileSystem fsystem) throws IOException{
		FileStatus fs = fsystem.getFileStatus(path);
		if(fs.isDirectory()){
			System.out.println("Directory: " + fs.getPath().toString());
			FileStatus[] fss = fsystem.listStatus(path);
			for(FileStatus f : fss){
				lsFile(f.getPath(),fsystem);
			}
		}else{
			System.out.println("File Name is: " + fs.getPath().toString() +",Size is: " + fs.getLen()/1024 + "KB");
		}
	}
}