首页 > 代码库 > 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");
		}
	}
}

Hadoop-2.4.1学习之FileSystem及实战