[UNIX/C/C++] 유닉스에서 디렉토리 다루기

개발 노트 2009. 1. 21. 18:32 posted by 무병장수권력자


유닉스에서 디렉토리 다루기

작성자 : 김문규
최초 작성일 : 2009. 1.21

1. 들어가며
서버 프로그래밍이든 클라이언트 프로그래밍이든 중요하게 다루어 지는 부분은 파일 시스템을 액세스해서 로컬 자원의 정보를 획득하는 것이 아닐까요?
대부분의 프로그래밍 책에서 파일을 열고 닫는 것을 많이 다룹니다. 그런데, 디렉토리에 대한 내용은 많이 보지 못한 것 같습니다.

그래서, 이번 포스트의 주제는 '유닉스에서 디렉토리 다루기' 입니다.

2. 디렉토리 다루기
특정 디렉토리부터 하위 디렉토리에 있는 파일 또는 디렉토리를 검색하는 알고리즘을 생각해 보겠습니다.
1) 현재 디렉토리에 존재하는 모든 파일 검색
2) 검색된 항목이 파일이면 다음
3) 검색된 항목이 디렉토리이면 1)로 가서 다시 검색

이를 구현시에는 다음과 같은 기능이 필요합니다.
1) 현재 디렉토리의 파일 리스팅
2) 리스팅된 파일이 일반 파일인지 디렉토리인지 구분하기
3) 재귀 함수 호출

이번 주제에 맞게 1), 2)에 대해서 간단한 예제와 함께 알아 보겠습니다.

1)디렉토리 리스팅 (Directory Listing)

디렉토리 리스팅을 위해서는 다음과 같은 구조체와 함수들을 사용하면 됩니다.

#include <dirent.h>

struct   dirent
{
    long                  d_ino;                                 // inode 넘버
    off_t                  d_off;                                 // offset
    unsigned short   d_reclen;                          // d_name 길이
    char                  d_name[NAME_MAX+1];     // 파일이름
}

DIR*  opendir(const  char*  name);                 // 열기
int   closedir(DIR*  dp);                                    // 닫기
struct  dirent*  readdir(DIR*  dp);                    // 읽기

간단한 예제 입니다.
#include <stdio.h>
#include <dirent.h>
int main (void)
{  
    DIR *pDir = NULL;
    dirent *pFile = NULL;
    pDir = opendir(".");
    if(!pDir) {
        printf("ERROR\n");
    }
    while( (pFile = readdir(pDir)) != NULL )
    {
        printf("%s\n", pFile->d_name);
    }
    closedir(pDir);
    return 0;


2) 파일 속성 알아내기

파일 속성을 알아내기 위해서는 다음과 같은 구조체와 함수들을 사용하면 됩니다.

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// 입력 변수만 조금 다를 뿐 기능은 같습니다.
int stat(const char *file_name, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *file_name, struct stat *buf);

struct stat
{
    dev_t         st_dev;      /* device */
    ino_t         st_ino;      /* inode */
    mode_t        st_mode;     /* protection */
    nlink_t       st_nlink;    /* number of hard links */
    uid_t         st_uid;      /* user ID of owner */
    gid_t         st_gid;      /* group ID of owner */
    dev_t         st_rdev;     /* device type (if inode device) */
    off_t         st_size;     /* total size, in bytes */
    unsigned long st_blksize;  /* blocksize for filesystem I/O */
    unsigned long st_blocks;   /* number of blocks allocated */
    time_t        st_atime;    /* time of last access */
    time_t        st_mtime;    /* time of last modification */
    time_t        st_ctime;    /* time of last change */
};

모든 필드가 각각의 의미를 가지고 있지만 이번 포스트에서는 관심 있는 플래그는 st_mode 입니다. 이 값이 파일의 성격을 알려주는 플래그이거든요.

이 값은 다음의 매크로를 이용해서 확인 가능합니다.
S_ISLNK(m)  is it a symbolic link?
S_ISREG(m)  regular file?
S_ISDIR(m)  directory?
S_ISCHR(m)  character device?
S_ISBLK(m)  block device?
S_ISFIFO(m) fifo?
S_ISSOCK(m) socket?

예제 코드로 설명한 내용을 확인해 보겠습니다.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
int main (void)
{  
    DIR *pDir = NULL;
    dirent *pFile = NULL;
    struct stat buf;
    pDir = opendir(".");
    if(!pDir) {
        printf("ERROR\n");
    }
    while( (pFile = readdir(pDir)) != NULL )
    {
        memset(&buf, 0, sizeof(struct stat));
        lstat(pFile->d_name, &buf);                    // buf에 stat 정보 저장
        if(S_ISDIR(buf.st_mode)) printf("[DIR]%s\n", pFile->d_name);
        else if(S_ISREG(buf.st_mode)) printf("[FILE]%s\n", pFile->d_name);
        else printf("[ELSE]%s\n", pFile->d_name);
    }
    closedir(pDir);
    return 0;
}  

3. 마치며
이 방법은 유닉스와 리눅스에서만 사용가능 합니다. 흠흠. 기왕이면 윈도우에서도 사용가능 했으면 좋았을 텐데요.
그럼 즐프하세요.