자바 인터페이스 디렉터리 생성,질의



디렉터리

FileSystem은 디렉터리를 생성하기 위한 메소드를 제공한다.

public coolean mkdirs(Path f) throws IOException

이 메소드는 java.io.File의 mkdirs() 메소드처럼 존재하지 않은 모든 부모 디렉터리를 생성한다. 디렉터리가 성공적으로 생성되면 true를 반환한다. 파일을 쓸 때 자동으로 create() 메소드를 호출하여 부모 디렉터리를 생성하므로, 명시적으로 디렉터리를 생성할 필요는 없다.


파일 메타데이터: FileStatus

모든 파일시스템은 디렉터리 구조를 탐색하고 저장된 파일과 디렉터리에 대한 정보를 추출하는 기능을 제곤한다. FileStatus 클래스는 파일 길이, 블록 크기, 복제, 수정 시간, 소유권, 권한 정보와 같은 파일과 디렉터리에 대한 파일시스템 메타데이터를 포함하고 있다.


public class ShowFileStatusTest {
    private MiniDFSCluster cluster;
    private FilSystem 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(expected = FileNotFoundException.class)
    public void thorwsFileNotFoundForNonExistentFile() 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(false));
        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 을 일으킨다. 단지 파일이나 디렉터리의 존재 여부가 궁금하다면 FileSystem의 exists() 메소드를 호출하는 것이 좋다.


public boolean exists(Path f) throws IOException


파일 목록 조회


파일이나 디렉터리에 대한 정보를 찾는 것도 필요하지만 , 특정 디렉터리의 내용(파일이나 서브디렉터리 목록)을 조회할 필요도 있다. 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, PathFileter filter) throws IOException


주어진 인자가 하나의 파일이면 길이가 1인 FileStatus 객체 배열을 반환한다. 인자가 디렉터리면 해당 디렉터리에 포함된 모든 파일과 디렉터리의 FileStatus 객체 배열(0 또는 그 이상)을 반환한다. Path Fileter를 인자로 가지는 메소드는 특정 패턴에 일치하는 파일과 디렉토리만 처리한다. 마지막으로 경로의 배열을 지정하면 각 경로마다 순차적으로 단일 경로 listStatus() 메소드를 호출하여 fileStatus 객체 배열에 모든 결과를 누적시킨다. 이 메소드는 파일시스템 트리의 여러 부분에 있는 파일을 모두 처리하기 위해 입력 파일이 목록을 구축할 때 유용하다. FileStatus 객체으 ㅣ배열을 Path 객체의 배열로 변환하기 위해 하둡 FileUtil의 stat2Paths() 메소드를 사용했다.


// 하둡 파일시스템의 경로 집합에 대한 파일 상태 보기
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);
        }
    }
}


이 프로그램은 경로 집합에 대한 디렉터리 목록을 모아서 보여준다.


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


파일 패턴

단인 연산이지만 파일의 집합을 처리해야 할 때도 있다. 예를 들얼 로그를 분석하는 맵리듀스 잡은 여러 디렉터리에 있는 한 달 분량의 파일을 모두 처리해야 한다. 모든 파일과 디렉터리를 일일이 나열하는 것보다 단일 표현식으로 와일드카드 문자를 이용하여 다중 파일을 매칭하는 글로빙(globbing)으로 알려진 연산을 사용하는 것이 더 편리하다. 하둡은 글로빙을 지원하는 두개의 FileSystem 메서드를 제공한다.


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


globStatus() 메소드는 주어진 패턴에 매칭되는 경로에 대한 FileStatus 객체의 배열을 경로를 기준으로 정렬하여 반환한다. 옵션인 PathFilter를 명시하면 좀 더 매칭에 제약을 가할 수 있다. 하둡은 유닉스 bash 쉘과 동일한 글로브 문자 집합을 지원한다.


글로브 이름 일치되는 대상
* 별표 0개 이상의 문자
? 물음표 단일 문자
[ab] 문자 집합 집합 {a, b}에 있는 단일 문자
[^ab] 부정된 문자 집합 집합 {a, b}에 없는 단일 문자
[a-b] 문자 영역 (닫힌) 영역 [a, b]에 있는 단일 문자(사전적으로 a는 b보다 작거나 같다)
[^a-b] 부정된 문자 영역 (닫힌) 영역 [a, b]에 없는 단일 문자(사전적으로 a는 b보다 작거나 같다)
{a, b} 양자택일 표현 a 또는 b에 일치
\c 이스케이프 문자 문자 c가 메타문자일 때 문자 c와 일치


로그파일이 날짜에 의해 계층적으로 구성된 디렉터리에 저장되어 있다고 가정했을 때 2007년 마지막 날의 로그파일은 /2007/12/31 로 명명된 디렉터리에 있을 것이다.

/
|-- 2007/
|   |__ 12/
|       |-- 30/
|       |__ 31/
|__ 2008/
    |__ 01/
        |-- 01/
        |__ 02/

파일 글로브와 이에 대응하는 사례 표


글로브 표현
/* /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

글로브 패턴을 사용하더라도 접근하고 싶은 파일의 집합을 완전히 표현할 수는 없다. 예를 들어 글로브 패턴으로 특정 파일을 제거하는 것은 불가능하다. FilyySystem의 listStatus() 와 globStatus() 메소드는 프로그래밍 방식으로 매칭을 허용하는 PathFilter를 옵션으로 지원한다.


package org.apache.hadoop.fs;

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


PathFilter는 File 객체보다 Path 객체를 위한 java.io.FileFilter에 대응된다. 정규표현식에 매칭되는 특정 경로를 제외하기 위한 PathFilter의 사용법 예제이다.


//정규표현식에 매칭되는 특정 경로를 제외하기 위한 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);
    }
}


필터는 정규표현식에 매칭되지 않는 파일만 통과시킨다. 글로빙은 포함할 파일의 초기 집합을 추출하고, 필터는 그 결과에서 필요 없는 파일을 제외할 때 사용한다.


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


실행하면 2007년 1월 1일 부터 12월 30일 까지의 데이터만 반환될 것이다. 필터는 Path로 표시되는 파일의 이름에만 적용된다. 따라서 생성 시간과 같은 파일의 속성은 사용할 수 없다. 하지만 글로빙 패턴이나 정규표현식으로 수행할 수 없는 매칭 작업도 할 수 있다. 예를 들어 날짜별로 구성된 디렉터리 구조에 파일을 저장하면 지정된 날짜 구간에 해당하는 파일을 PathFilter로 제외할 수 있다.


데이터 삭제

FileSystem의 delete() 메소드를 사용하면 파일과 디렉토리를 영구적으로 삭제할 수 있다.


public boolean delete(Path f, boolean recursive) throws IOException


여기서 경로 f가 파일이거나 비어 있는 디렉터리면 recursive 인자는 무시된다. recursive가 true고 디렉터리에 내용물이 있으면 해당 디렉터리가 삭제된다. 그렇지 않으면 IOException이 발생한다.