9.5.6 文件系统查询
同样,Java API提供了文件系统的基本查询接口。通过这个接口,可以查询系统的元数据信息和文件目录结构,并可以进行更复杂的目录匹配等操作。下面将一一进行介绍。
1.文件元数据:Filestatus
任何文件系统要具备的重要功能就是定位其目录结构及检索器存储的文件和目录信息。FileStatus类封装了文件系统中文件和目录的元数据,其中包括文件长度、块大小、副本、修改时间、所有者和许可信息等。
FileSystem的getFileStatus()方法提供了获取一个文件或目录的状态对象的方法,如例9-5所示。
例9-5:获取文件状态信息
public class ShowFileStatusTest{
private MiniDFSCluster cluster;//use an in-process HDFS cluster for testing
private FileSystem fs;
@Before
public void setUp()throws IOException{
Configuration conf=new Configuration();
if(System.getProperty("test.build.data")==null){
System.setProperty("test.build.data","/tmp");
}
cluster=new MiniDFSCluster(conf,1,true, null);
fs=cluster.getFileSystem();
OutputStream out=fs.create(new Path("/dir/file"));
out.write("content".getBytes("UTF-8"));
out.close();
}
@After
public void tearDown()throws IOException{
if(fs!=null){fs.close();}
if(cluster!=null){cluster.shutdown();}
}
@Test(expected=FileNotFoundException.class)
public void throwsFileNotFoundForNonExistentFile()throws IOException{
fs.getFileStatus(new Path("no-such-file"));
}
@Test
public void fileStatusForFile()throws IOException{
Path file=new Path("/dir/file");
FileStatus stat=fs.getFileStatus(file);
assertThat(stat.getPath().toUri().getPath(),is("/dir/file"));
assertThat(stat.isDir(),is(false));
assertThat(stat.getLen(),is(7L));
assertThat(stat.getModificationTime(),
is(lessThanOrEqualTo(System.currentTimeMillis())));
assertThat(stat.getReplication(),is((short)1));
assertThat(stat.getBlockSize(),is(6410241024L));
assertThat(stat.getOwner(),is("tom"));
assertThat(stat.getGroup(),is("supergroup"));
assertThat(stat.getPermission().toString(),is("rw-r—r—"));
}
@Test
public void fileStatusForDirectory()throws IOException{
Path dir=new Path("/dir");
FileStatus stat=fs.getFileStatus(dir);
assertThat(stat.getPath().toUri().getPath(),is("/dir"));
assertThat(stat.isDir(),is(true));
assertThat(stat.getLen(),is(0L));
assertThat(stat.getModificationTime(),
is(lessThanOrEqualTo(System.currentTimeMillis())));
assertThat(stat.getReplication(),is((short)0));
assertThat(stat.getBlockSize(),is(0L));
assertThat(stat.getOwner(),is("tom"));
assertThat(stat.getGroup(),is("supergroup"));
assertThat(stat.getPermission().toString(),is("rwxr-xr-x"));
}
}
如果文件或者目录不存在,就会抛出FileNotFoundException异常;如果只对文件或目录是否存在感兴趣,那么用exists()方法更方便:
public boolean exists(Path f)throws IOException
2.列出目录文件信息
查找文件或者目录信息很有用,但是,有时需要列出目录的内容,这需要使用lis-tStatus()方法,代码如下:
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
当传入参数是一个文件时,它会简单地返回长度为1的FileStatus对象的一个数组。当传入参数为一个目录时,它会返回0个或多个FileStatus对象,代表该目录所包含的文件和子目录。
我们看到listStatus()有很多重载方法,可以使用PathFilter来限制匹配的文件和目录。如果把路径数组作为参数来调用listStatus()方法,其结果与一次对多个目录进行查询、再将FileStatus对象数组收集到一个单一的数组的结果是相同的。当然我们可以感受到,前者更为方便。例9-6是一个简单的示范。
例9-6:显示Hadoop文件系统中的一个目录的文件信息
package cn.edn.ruc.cloudcomputing.book.chapter09;
import java.util.*;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FileSystem;
public class ListStatus{
public static void main(String[]args)throws Exception{
String uri=args[0];
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(URI.create(uri),conf);
Path[]paths=new Path[args.length];
for(int i=0;i<paths.length;i++){
paths[i]=new Path(args[i]);
}
FileStatus[]status=fs.listStatus(paths);
Path[]listedPaths=FileUtil.stat2Paths(status);
for(Path p:listedPaths){
System.out.println(p);
}
}
}
配置应用参数可以查看文件系统的目录,可以查看HDFS中对应文件目录下的文件信息。
3.通过通配符实现目录筛选
有时候我们需要批量处理文件,比如处理日志文件,这时可能要求MapRedece任务分析一个月的文件。这些文件包含在大量目录中,这就要求我们进行一个通配符操作,并使用通配符核对多个文件。Hadoop为通配符提供了两个方法,可以在FileSystem中找到:
public FileStatus[]globStatus(Path pathPattern)throws IOException
public FileStatus[]globStatus(Path pathPattern, PathFilter filter)throws IOException
globStatus()返回了其路径匹配所提供的FileStatus对象数组,再按路径进行排序,其中可选的PathFilter命令可以进一步限定匹配。
表9-2是Hadoop支持的一系列通配符。
下面通过例子进行详细说明,假设一个日志文件的存储目录是分层组织的,其中目录格式为年/月/日:/2009/12/30、/2009/12/31、/2010/01/01、/2010/01/02。表9-3是通配符的部分样例。
4.PathFilter对象
使用通配符有时也不一定能够精确地定位到要访问的文件集合,比如排除一个特定的文件,这时可以使用FileSystem中的listStatus()和globStatus()方法提供可选的PathFileter对象来通过编程的办法控制匹配结果,如下面的代码所示。
package org.apache.hadoop.fs;
public interface PathFilter{
boolean accept(Path path);
}
下面来看一个PathFilter的应用,如例9-7所示。
例9-7:使用PathFilter排除匹配正则表达式的目录
public class RegexExcludePathFilter implements PathFilter{
private final String regex;
public RegexExcludePathFilter(String regex){
this.regex=regex;
}
public boolean accept(Path path){
return!path.toString().matches(regex);
}
}
这个过滤器将留下与正则表达式不匹配的文件。