Jul
30
이번에 dirent 와 stat 을 이용하여 작업을 하면서 알게된 내용들을 간단하게 정리했다.
dirent
dirent 는 디렉토리 정보를 담는 구조체이다.
dirent 와 scandir() 을 사용하면 디렉토리에 어떤 파일들이 있는지 간략하게 알 수 있는 속성과 파일 리스트 포인터를 이용할 수 있다.
struct dirent { #ifndef __USE_FILE_OFFSET64 __ino_t d_ino; __off_t d_off; #else __ino64_t d_ino; __off64_t d_off; #endif unsigned short int d_reclen; unsigned char d_type; char d_name[256]; /* We must not include limits.h! */ };
구조체 내용 중, d_type 으로 파일의 속성을 파악할 수 있는데, 종류는 다음과 같다.
#ifdef __USE_BSD /* File types for `d_type'. */ enum { DT_UNKNOWN = 0, # define DT_UNKNOWN DT_UNKNOWN DT_FIFO = 1, # define DT_FIFO DT_FIFO DT_CHR = 2, # define DT_CHR DT_CHR DT_DIR = 4, # define DT_DIR DT_DIR DT_BLK = 6, # define DT_BLK DT_BLK DT_REG = 8, # define DT_REG DT_REG DT_LNK = 10, # define DT_LNK DT_LNK DT_SOCK = 12, # define DT_SOCK DT_SOCK DT_WHT = 14 # define DT_WHT DT_WHT }; /* Convert between stat structure types and directory types. */ # define IFTODT(mode) (((mode) & 0170000) >> 12) # define DTTOIF(dirtype) ((dirtype) << 12) #endif
stat
stat 은 파일 속성을 가져오는 함수이며, 구조체이다. stat 을 호출하면, 입력한 파일에 대한 속성들이 struct stat 구조체에 입력된다.
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ 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 ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of 512B 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 status change */ };
Eaxmple
아래는 stat 과 scandir 을 이용한 예제 프로그램이다.
현재 디렉토리 내에 있는 모든 파일들을 최근 수정한 순서대로 검색하며 각각의 파일명과 사이즈(Byte)를 표시한다.
만약, 디렉토리 안에 있는 파일들의 용량의 10M가 넘어가면, 그 이후부터는 파일을 삭제한다.
즉, 디렉토리에 있는 파일들의 용량이 10M가 넘어가면 오래된 파일부터 삭제하는 것이다.
그리고 파일을 검색하는 도중 파일명에 .wav(wav 파일)이 들어있으면 “Found wav file” 을 표시한다.
#include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <errno.h> #define TARGET_DIR "." #define LIMIT_SIZE 10485760 // 10M int file_select( const struct dirent *d ); int cmp_time(const struct dirent **e1, const struct dirent **e2); int main(int argc, char** argv) { struct dirent **namelist; struct stat tmp_stat; unsigned long total_size; char* pszFilename; int iCnt; int i; int iRet; char* pRet; iCnt = scandir(TARGET_DIR, &namelist, file_select, cmp_time); if(iCnt < 0) { printf("Could not scanning.. err:%d, msg:%s\n", errno, strerror(errno)); return 0; } total_size = 0; printf("Scan files:%d\n", iCnt); for(i = 0; i < iCnt; i++) { asprintf(&pszFilename, "%s/%s", TARGET_DIR, namelist[i]->d_name); stat(pszFilename, &tmp_stat); printf("filename: %s, size:%ld\n", pszFilename, tmp_stat.st_size); pRet = strstr(namelist[i]->d_name, ".wav"); if(pRet != NULL) { printf("Found wav file!\n"); } total_size += tmp_stat.st_size; if(total_size > LIMIT_SIZE) { total_size -= tmp_stat.st_size; printf("Delete limit overed files... name: %s\n", pszFilename); iRet = remove(pszFilename); if(iRet == -1) { printf("Err! Could not delete file. name:%s, err:%d, msg:%s\n", pszFilename, errno, strerror(errno)); } } free(pszFilename); free(namelist[i]); } free(namelist); printf("totalSize %lu\n", total_size); return 0; } /** * */ int file_select(const struct dirent *entry) { if(entry->d_type == DT_DIR) { return 0; } return 1; } /** * */ int cmp_time(const struct dirent **e1, const struct dirent **e2) { int iRet; struct stat sb1; struct stat sb2; char* filename_e1; char* filename_e2; asprintf(&filename_e1, "%s/%s", TARGET_DIR, (*e1)->d_name); asprintf(&filename_e2, "%s/%s", TARGET_DIR, (*e2)->d_name); iRet = stat(filename_e1, &sb1); if(iRet == -1) { printf("Error occured! name:%s, err:%d, msg:%s\n", filename_e1, errno, strerror(errno)); free(filename_e1); free(filename_e2); return -1; } iRet = stat(filename_e2, &sb2); if(iRet == -1) { printf("Error occured! Err:%d, Msg:%s\n", errno, strerror(errno)); free(filename_e1); free(filename_e2); return -1; } free(filename_e1); free(filename_e2); return sb1.st_mtime < sb2.st_mtime; }