> Linux集群 > Hadoop >

hadoop FileSystem查询文件系统

文件元数据:Filestatus

任何文件系统的一个重要特征是定位其目录结构及检索其存储的文件和目录信息的能力。FileStatus类封装了文件系统中文件和目录的元数据,包括文件长度、块大小、副本、修改时间、所有者、所属组以及许可信息。

代码:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class FileStatus implements Writable, Comparable {
 
  private Path path;
  private long length;
  private boolean isdir;
  private short block_replication;
  private long blocksize;
  private long modification_time;
  private long access_time;
  private FsPermission permission;
  private String owner;
  private String group;
  
  public FileStatus() { this(0, false, 0, 0, 0, 0, null, null, null, null); }
 
 public FileStatus(long length, boolean isdir, int block_replication,
                    long blocksize, long modification_time, long access_time,
                    FsPermission permission, String owner, String group,
                    Path path) {
    this.length = length;
    this.isdir = isdir;
    this.block_replication = (short)block_replication;
    this.blocksize = blocksize;
    this.modification_time = modification_time;
    this.access_time = access_time;
    this.permission = (permission == null) ?
                      FsPermission.getDefault() : permission;
    this.owner = (owner == null) ? "" : owner;
    this.group = (group == null) ? "" : group;
    this.path = path;
  }
 
...
}

FileSystem的getFileStatus()提供了获取一个文件或目录的状态对象的方法。例3-5展示了它的用法。

例3-5:展示文件状态信息

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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(64 * 1024 * 1024L)); 
    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()方法会更方便

 

1
public boolean exists(Path f) throws IOException
  列出文件

查找一个文件或目录的信息很实用,但有时我们还需要能够列出目录的内容。这就是listStatus()方法的功能:

 
1
2
3
4
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对象,代表着此目录所包含的文件和目录。

重载方法允许我们使用PathFilter来限制匹配的文件和目录,示例参见后文。如果把路径数组作为参数来调用listStatus方法,其结果是与依次对每个路径调用此方法,再将FileStatus对象数组收集在一个单一数组中的结果是相同的,但是前者更为方便。这在建立从文件系统树的不同部分执行的输入文件的列表时很有用。例3-6是这种思想的简单示范。注意FIleUtil中stat2Paths()的使用,它将一个FileStatus对象数组转换为Path对象数组。

例3-6:显示一个Hadoop文件系统中一些路径的文件信息

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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); 
    } 
  } 
}

文件格式

在一步操作中处理批量文件,这个要求很常见。举例来说,处理日志的MapReduce作业可能会分析一个月的文件,这些文件被包含在大量目录中。Hadoop有一个通配的操作,可以方便地使用通配符在一个表达式中核对多个文件,不需要列举每个文件和目录来指定输入。Hadoop为执行通配提供了两个FileSystem方法:

1
2
public FileStatus[] globStatus(Path pathPattern) throws IOException 
public FileStatus[] globStatus(Path pathPattern, PathFilter filter) throws IOException

globStatus()返回了其路径匹配于所供格式的FileStatus对象数组,按路径排序。可选的PathFilter命令可以进一步指定限制匹配。

Hadoop支持的一系列通配符与Unix bash相同(见表3-2)。

表3-2:通配符及其作用

通配符

名称

匹配

*

星号

匹配0或多个字符

问号

匹配单一字符

[ab]

字符类别

匹配{a,b}中的一个字符

 

 

[^ab]

非字符类别

匹配不是{a,b}中的一个字符

[a-b]

字符范围

匹配一个在{a,b}范围内的

字符(包括ab),a在字典

顺序上要小于或等于b

[^a-b]

非字符范围

匹配一个不在{a,b}范围内

的字符(包括ab),a在字

典顺序上要小于或等于b

{a,b}

或选择

匹配包含a或b中的一个的语句

\c

转义字符

匹配元字符c

以下是一些文件通配符及其扩展。

通配符

扩展

/*

/2007/2008

/*/*

/2007/12 /2008/01

/*/12/*

/2007/12/30 /2007/12/31

/200?

/2007 /2008

/200[78]

/2007 /2008

/200[7-8]

/2007 /2008

/200[^01234569]

/2007 /2008

/*/*/{31,01}

/2007/12/31 /2008/01/01

/*/*/3{0,1}

/2007/12/30 /2007/12/31

/*/{12/31,01/01}

/2007/12/31 /2008/01/01

 

PathFilter对象

通配格式不是总能够精确地描述我们想要访问的文件集合。比如,使用通配格式排除一个特定的文件就不太可能。FileSystem中的listStatus()和globStatus()方法提供了可选的PathFilter对象,使我们能够通过编程方式控制匹配:

 
1
2
3
4
5
package org.apache.hadoop.fs; 
 
public interface PathFilter { 
boolean accept(Path path); 
}

PathFilter与java.io.FileFilter一样,是Path对象而不是File对象。

例3-7展示了一个PathFilter,用于排除匹配一个正则表达式的路径。

 
1
2
3
4
5
6
7
8
9
10
11
12
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); 
  } 
}

 
这个过滤器只留下与正则表达式不同的文件。我们将它与预先剔除一些文件集合的通配配合:过滤器用来优化结果。例如:
 
1
2
s.globStatus(new Path("/2007/*/*"),  
new RegexExcludeFilter("^.*/2007/12/31$"))

 

参考:Hadoop权威指南第2版中文版



(责任编辑:IT)