HDFS——查询文件系统详解

本文详细介绍了HDFS中的文件元数据,包括FileStatus类以及如何获取文件状态信息。接着讨论了如何列出目录内容,使用listStatus()方法及通配符进行文件匹配。还讲解了globStatus()方法在处理批量文件时的作用,以及如何通过PathFilter对象进行文件过滤,以实现更复杂的筛选需求。文章以实例展示了PathFilter如何排除特定文件或根据正则表达式筛选文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 文件元数据:FileStatus

任何文件系统的一个重要特征都是提供其目录结构浏览和检索它所存文件和目录相关信息的功能。FileStatus类封装了文件系统中文件和目录的元数据,包括文件长度、块大小、复本、修改时间、所有者、权限信息。

FileStatus的getFileStatus()方法用于获取文件或目录的FileStatus对象。看下面:

范例1,展示文件状态信息

public class ShowFileStatusTest{
    
    private MiniDFSCluster cluster;//use an in-process 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.Builder(conf).build();
        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
    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.isDirectory(),is(false));
        assertThat(stat.getLen(),is(7L));
        assertThat(stat.getModificationTime(),is(lessThanOrEqualTo(System.CurrentTimeMillis())));
        assertThat(stat.getReplication(),is((short)1));
        assertThat(stat.getBlockSize(),is(128*1024*1024L));
        assertThat(stat.getOwner(),is(System.getProperty("user.name")));
        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.isDirectory(),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(System.getProperty("user.name")));
        assertThat(stat.getGroup(),is("supergroup"));
        assertThat(stat.getPermission().toString(),is("rwxr-xr-x"));
    }
}

如果文件或目录均不存在,会抛出一个FileNotFoundException异常。但如果只是想检查文件或目录是否存在,那么调用exists()方法会更方便:public boolean exists(Path f) throws IOException

2. 列出文件

查找一个文件或目录相关的信息很实用,但通常还需要能够列出目录中的内容。

以下就是FileSystem的listStatus()方法的功能:

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对象数组累积存入同一数组中,该方法更方便。在文件系统树的不同分支构建输入文件列表时,这是很有用的。举个例子(范例2),Hadoop中的FileUtil中stat2Path()方法的使用,它将一个FileStatus对象数组转换为一个Path对象数组:

范例2:

范例2:显示Hadoop文件系统中一组路径的文件信息

public class ListStatus{
    public static void main(String[] args) throws Exception{
        String uri = arg[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++){
            path[i] = new Path(args[i]);
        }
        
        FileStatus[] status = fs.listStatus(paths);
        Path[] listedPaths = FileUtil.stat2Paths(status);
        for(Path p : listedPaths){
            System.out.println(p);
        }
    }
}

程序运行示例结果:

% hadoop ListStatus hdfs://localhost/ hdfs://localhost/user/tom
hdfs://localhost/user
hdfs://localhost/user/tom/books
hdfs://localhost/user/tom/quangle.txt

3. 文件模式——通配符

在单个操作中处理一批文件是一个很常见的需求。例如,一个用于处理日志的MapReduce作业可能需要分析一个月包含在大量目录中的日志文件。在一个表达式中使用通配符来匹配多个文件是比较方便的,无需列举每个文件和目录来指定输入,该操作称为“通配”,Hadoop为执行通配提供了两个FileSystem方法。

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

globStatus()方法返回路径格式与指定模式匹配的所有FileStatus对象组成的数组,并按路径排序。PathFilter命令作为可选项可以进一步对匹配结果进行限制。

Hadoop支持的通配符与Unix bash shell支持的相同,见下表

通配符以及含义
通配符名称匹配
*星号匹配 0 或多个字符
问号匹配单一字符
[ab]字符类匹配{a,b}集合中的一个字符
[^ab]非字符类匹配非{a,b}集合中的一个字符
[a-b]字符范围匹配一个在{a,b}范围内的字符,包括a和b,a在字典顺序上要小于或等于b
[^a-b]非字符范围匹配一个不在{a,b}范围内的字符,包括a和b,a在字典顺序上要小于或等于b
{a,b}或选择匹配包含 a 或 b 中的一个表达式
\c转义字符匹配元字符c

 

 

 

 

 

 

 

 

 

 

 假设有日志文件存储在按日期分层组织的目录结构中,那么2019年的最后一天的日志文件就会保存在名为/2019/12/31的目录中。

下表是常用文件通配符的示例

常用的时间日期通配符
通配符扩展
/*/2018/2019
/*/*/2018/12/2019/01
/*/12/*/2018/12/01/2018/12/02
/201?/2017/2018
/201[78]/2017/2018
/201[7-8]/2017/2018
/201[^01234569]/2017/2018
/*/*/{31,01}/2017/12/31/2017/01/01
/*/*/3{0,1}/2017/12/30/2017/12/31
/*/{12/31,01/01}/2017/12/31/2018/01/01

 

 

 

 

 

 

 

 

 

 

 

 

4. PathFilter对象——过滤文件

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

package org.apache.hadoop.fs;

public insterface PathFilter{
    boolean accept(Path path);
}

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

下面举个例子(范例3),用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);
    }
}

 这个过滤器只传递不匹配于正则表达式的文件。在通配符中选出一组需要包含的初始文件之后,过滤器可优化其结果。如下示例将扩展到/2017/12/30:

fs.globStatus(new Path("/2017/*/*"),new RegexExcluderFilter("^.*/2017/12/31$"))

以Path为代表,过滤器只能作用于文件名。不能针对文件的属性(例如创建时间)来构建过滤器。但是,过滤器却能实现通配符模式和正则表达式都无法完成的匹配任务。例如,如果将文件存储在按照日期排列的目录结构中,则可以写一个PathFilter选出给定时间范围内的文件。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值