HOME > linux > library

Linux - fts_open(), fts_read()로 디렉토리 파일들을 찾는 예제

By JS | 15 Oct 2019

리눅스/유닉스 계열에서 디렉토리의 모든 파일 리스트를 얻는 기능을 구현하려고 할 때 fts 라이브러리를 이용하면 됩니다.

  • fts_open(): 인자로 전달된 디렉토리에 대한 FTS 객체를 리턴합니다.
  • fts_read(): FTS 객체에서 파일에 대한 FTSENT 객체를 리턴합니다.

처음 본 라이브러리를 예제로 만들어본 것이기 때문에, 설명이 부족할 수 있습니다. 참고해서 봐주세요. 먼저 예제 코드 및 출력 결과를 보고, 그 이후에 부분적으로 살펴보겠습니다.

예제

다음 예제는 "./" 디렉토리에 대한 모든 파일을 출력합니다. fts라이브러리는 recursive로 폴더를 순회하며 파일들을 모두 찾아냅니다.

예제는 안드로이드 프레임워크 코드를 참고하여 작성하였습니다.

main.cpp

#include <errno.h>
#include <string.h>
#include <fts.h>
#include <iostream>

using namespace std;

int main() {
    std::string path("./");

    FTS *fts;
    char *argv[] = { (char*) path.c_str(), nullptr };
    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
        if (errno != ENOENT) {
            cout << "Failed to fts_open " << path;
        }
        return -1;
    }

    FTSENT *p;
    while ((p = fts_read(fts)) != nullptr) {
        switch (p->fts_info) {
            case FTS_DP:
                cout << "Directory: " << p->fts_path << "\n";
                break;
            case FTS_F:
                cout << "File: " << p->fts_path << "\n";
                break;
            case FTS_SL:
            case FTS_SLNONE:
                cout << "Symbolic link: " << p->fts_path << "\n";
                break;
        }
    }
    fts_close(fts);

    return 0;
}

Build & Run

코드를 실행하기 전에 현재 디렉토리 상태는 다음과 같습니다.

$ tree
.
├── aa
│   └── file2.txt
├── bb
│   ├── dd
│   │   ├── file6.txt
│   │   └── file7.txt
│   ├── file3.txt
│   ├── file4.txt
│   └── file5.txt
├── cc
│   ├── file8.txt
│   ├── file9.txt
│   └── symbolic.txt -> file8.txt
├── file1.txt
├── main.cpp
└── main

다음 명령어로 빌드 및 실행을 하였습니다.

$ g++ main.cpp -o main
$ ./main

결과를 보시면 "./" 아래의 모든 파일들이 출력되었습니다.

File: ./bb/file5.txt
File: ./bb/dd/file7.txt
File: ./bb/dd/file6.txt
Directory: ./bb/dd
File: ./bb/file3.txt
File: ./bb/file4.txt
Directory: ./bb
File: ./aa/file2.txt
Directory: ./aa
Symbolic link: ./cc/symbolic.txt
File: ./cc/file9.txt
File: ./cc/file8.txt
Directory: ./cc
File: ./file1.txt
File: ./main.cpp
File: ./main
Directory: ./

fts_open()

다음 처럼 fts_open()을 사용하여 FTS 객체를 얻을 수 있으며, 실패에 대한 예외처리를 할 수 있습니다. 인자로 파일 패스가 전달됩니다.

std::string path("./");
char *argv[] = { (char*) path.c_str(), nullptr };
if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
    if (errno != ENOENT) {
        cout << "Failed to fts_open " << path;
    }
    return -1;
}

옵션에 대한 의미는 다음과 같습니다. 더 자세한 것은 manpage를 확인해주세요.

  • FTS_PHYSICAL : This option causes the fts routines to return FTSENT structures for symbolic links
  • FTS_NOCHDIR : To allow descending to arbitrary depths and improve performance
  • FTS_XDEV : This option prevents fts from descending into directories that have a different device number

fts_read()

다음 처럼 fts_read()를 이용하여 디렉토리를 순회할 수 있습니다. FTSENT의 fts_path로 파일 패스를 얻을 수 있습니다.

FTSENT *p;
while ((p = fts_read(fts)) != nullptr) {
    switch (p->fts_info) {
        case FTS_DP:
            cout << "Directory: " << p->fts_path << "\n";
            break;
        case FTS_F:
            cout << "File: " << p->fts_path << "\n";
            break;
        case FTS_SL:
        case FTS_SLNONE:
            cout << "Symbolic link: " << p->fts_path << "\n";
            break;
    }
}

FTSENT의 구조는 다음과 같습니다.

typedef struct _ftsent {
  int fts_info;		     /*	status for FTSENT structure */
  char *fts_accpath;		     /*	access path */
  char *fts_path;		     /*	root path */
  size_t fts_pathlen;	     /*	strlen(fts_path) */
  char *fts_name;		     /*	file name */
  size_t fts_namelen;	     /*	strlen(fts_name) */
  long fts_level;		     /*	depth (-1 to N)	*/
  int fts_errno;		     /*	file errno */
  long long fts_number;	     /*	local numeric value */
  void *fts_pointer;		     /*	local address value */
  struct ftsent *fts_parent;	     /*	parent directory */
  struct ftsent *fts_link;	     /*	next file structure */
  struct ftsent *fts_cycle;	     /*	cycle structure	*/
  struct stat *fts_statp;	     /*	stat(2)	information */
} FTSENT;

그리고 위의 예제에서 사용한 FTS 파일 정보들은 다음과 같습니다. 더 자세한 것은 manpage를 확인해주세요.

  • FTS_DP : Directory 파일
  • FTS_F : 일반적인 파일
  • FTS_SL, FTS_SLNONE : Symbolic link 파일

fts_close()

FTS를 모두 사용하였으면 다음 코드로 close하면 됩니다.

fts_close(fts);

참고