15-4.파일 관리
가.기본적인 파일 관리
지금까지 알아본 파일 입출력 함수들은 파일에 저장된 데이터를 읽고 쓰는 함수들이었다. 이에 비해 파일 관리 함수들은 저장된 데이터를 대상으로 하는 것이 아니라 파일 그 자체를 대상으로 한다는 점이 다르다. 사용 방법이 간단하고 직관적이므로 함수의 원형만 소개하기로 한다.
다음 함수는 파일 또는 디렉토리의 보안 허가 상태(Permission) 즉 쓰기가 가능한지, 읽기 전용인지 등을 조사하는데 주로 파일이 존재하는지를 조사하는 목적으로 많이 사용된다. 파일을 액세스하기 전에 해당 파일이 실제로 존재하는지를 먼저 알아야 한다면 이 함수로 조사할 수 있다.
int _access(const char *path, int mode);
path에 조사할 파일의 경로를 주고 mode에 조사할 상태를 지정하는데 0은 존재, 2는 쓰기, 4는 읽기를 나타낸다. 요청한 허가 상태를 가지면 이 함수는 0을 리턴하며 그렇지 않으면 -1을 리턴한다. 예를 들어 Test.txt가 실제 존재하는 파일인지 알고 싶다면 if (_access("test.txt",0)==0) 조건문을 사용하면 된다. 다음 두 함수는 파일을 삭제한다. 삭제하고자 하는 파일의 경로를 인수로 전달해 주기만 하면 된다. 두 함수는 이름만 다르며 실제로는 같은 함수이다.
int remove(const char *path);
int _unlink(const char *filename);
다음 함수는 파일의 이름을 변경한다. 변경하고자 하는 파일의 이름과 새로 설정할 파일의 이름을 인수로 지정하면 된다. a.txt를 b.txt로 바꾸고 싶다면 rename("a.txt", "b.txt")를 호출한다.
int rename(const char *oldname, const char *newname);
다음 함수는 파일의 속성을 변경한다. 즉, 읽기 전용으로 만들 것인지 아니면 읽기 쓰기가 가능한 파일로 만들 것인지를 변경한다.
int _chmod(const char *filename, int pmode);
대상 파일의 이름과 새로 지정할 속성을 지정하되 속성은 _S_IWRITE, _S_IREAD 둘 중 하나를 주거나 아니면 둘 다 줄 수도 있다. 윈도우즈 환경에서는 쓰기 전용 속성이 존재하지 않으므로 실제로 이 함수는 읽기 전용인지 아니면 읽기 쓰기가 가능한지만을 변경할 수 있는 셈이다.
C 런타임 라이브러리 수준에서는 파일을 복사하는 함수가 제공되지 않는다. 그래서 앞 절의 cp예제처럼 파일 입출력 함수로 직접 파일의 내용을 복사해야 한다. 아니면 운영체제가 제공하는 API 함수를 사용할 수도 있는데 윈도우즈는 CopyFile(Ex)라는 파일 복사 함수를 별도로 제공하고 있다. 파일을 이동하는 함수도 역시 제공되지 않으므로 복사 후 삭제하든지 아니면 MoveFile(Ex) 등의 API 함수를 사용해야 한다.
나.파일 검색
파일 검색 함수는 특정한 조건에 맞는 파일을 검색한다. 예를 들어 a로 시작하고 확장자가 txt인 모든 파일(a*.txt)를 찾아 어떤 작업을 하고 싶다면 이 조건에 맞는 파일을 먼저 찾아야 한다. 파일을 검색하는 함수는 다음 세 함수이다.
intptr_t _findfirst(const char *filespec, struct _finddata_t *fileinfo);
int _findnext(intptr_t handle, struct _finddata_t *fileinfo);
int _findclose(intptr_t handle);
findfirst 함수의 filespec 인수로 검색식을 주면 조건에 맞는 첫 번째 파일을 찾아 fileinfo 구조체에 검색된 파일의 정보를 채워 준다. _finddata_t 구조체는 io.h 헤더 파일에 다음과 같이 정의되어 있다.
struct _finddata_t {
unsigned attrib;
time_t time_create; /* -1 for FAT file systems */
time_t time_access; /* -1 for FAT file systems */
time_t time_write;
_fsize_t size;
char name[260];
};
파일의 속성, 이름, 날짜, 크기 등에 대한 정보를 가지며 이 구조체를 참조하면 어떤 파일이 검색되었는지 알 수 있다. _findfirst 함수로 첫 번째 검색을 한 후 _findnext 함수로 조건이 일치하는 다음 파일을 계속 찾을 수 있으며 _findnext가 -1을 리턴할 때까지 반복하면 조건에 맞는 모든 파일을 다 찾게 된다. 검색이 끝나면 _findclose 함수로 검색을 종료한다.
검색 함수로 서브 디렉토리까지 검색하려면 재귀 호출을 사용한다. 파일 검색이 필요한 경우는 아주 흔한데 통상 C 런타임 함수를 직접 사용하는 경우보다 운영체제의 검색 함수를 사용하는 것이 더 좋다. 왜냐하면 운영체제는 C 런타임 함수의 검색 함수보다 훨씬 자세한 검색을 할 수 있기 때문이다. 14장의 재귀 호출편에서 API 함수를 사용한 디렉토리 검색 예제를 다룬 바 있으므로 14장의 예제를 참조하기 바란다.
다.디렉토리 관리
다음은 파일을 담는 그릇인 디렉토리 관련 함수에 대해 알아 보자. 다음 세 함수가 가장 기본적인 디렉토리 관리 함수이다.
int _chdir(const char *dirname);
int _mkdir(const char *dirname);
int _rmdir(const char *dirname);
_chdir 함수는 현재 디렉토리를 변경한다. 이 함수로 변경한 현재 디렉토리를 작업 디렉토리라고 하며 이후 사용되는 상대 경로들은 작업 디렉토리를 기준으로 한다. _mkdir은 디렉토리를 생성하며 _rmdir은 디렉토리를 제거하되 비어있지 않은 디렉토리는 삭제할 수 없다. 다음 함수는 현재 작업 디렉토리를 조사한다.
char *_getcwd(char *buffer, int maxlen);
다음 두 함수는 파일 경로를 각각의 요소로 분리한다. 파일 경로는 드라이브, 디렉토리, 파일명, 확장자로 구성되어 있는데 직접 문자열을 조작하는 것은 무척 번거로운 일이다. 디렉토리와 파일 이름에 공백이 들어갈 수 있고 파일명과 확장자를 구분하는 마침표도 임의의 개수만큼 들어갈 수 있기 때문에 생각보다 훨씬 더 까다롭다.
경로 관리 함수는 파일 시스템의 이름 규칙대로 정확하게 경로 요소를 분리하고 합쳐 주므로 간편하게 쓸 수 있다. 특히 윈도우즈에는 경로를 관리하는 대응되는 함수가 없기 때문에 이 두 함수가 무척 유용하게 사용된다.
void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
void _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext);
_splitpath 함수는 한 개의 입력 경로를 받아들여 이 경로를 요소별로 분리하여 네 개의 문자열 버퍼에 각각 저장한다. 이 함수를 호출하려면 분리된 요소를 저장할 4개의 버퍼를 미리 준비해야 하는데 관심없는 요소에 대해서는 NULL값을 전달해도 상관없다. 다음에 간단한 예제를 보도록 하자.
예 제 : splitpath
#include <Turboc.h>
void main()
{
char path[MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
strcpy(path,"c:\\My Document\\Test\\Report 2.5.bak");
_splitpath(path,drive,dir,fname,ext);
printf("파일명 = %s\n",fname);
}
다소 복잡한 경로에 저장되어 있는 파일의 완전 경로에서 파일 이름만 조사해서 출력해 보았다. _splitpath 함수는 다음과 같이 파일 요소를 분리하는데 어디까지가 디렉토리이고 어디까지가 파일 이름인지를 정확하게 판별해낸다. UNC도 인식하므로 네트워크 파일 경로도 잘 분리한다.
이렇게 분리된 경로는 _makepath 함수로 다시 하나로 합칠 수 있다. 물론 분리된 각 요소를 개별적으로 변경한 후 합치는 것도 가능한데 예를 들어 파일의 확장자만 다른 것으로 바꾼다거나 드라이브만 바꿀 수도 있다.
라.디스크 관리
다음 두 함수는 작업 드라이브를 조사하거나 변경한다. 드라이브는 번호로 표현하는데 1이 A, 2가 B, 3이 C순이다.
int _getdrive(void);
int _chdrive(int drive);
다음 함수는 디스크의 총 용량 및 남은 용량을 조사한다.
unsigned _getdiskfree(unsigned drive, struct _diskfree_t * driveinfo);
조사하고자 하는 드라이브의 번호를 주면 이 드라이브의 용량에 대한 정보를 다음 구조체에 채워준다.
struct _diskfree_t {
unsigned total_clusters;
unsigned avail_clusters;
unsigned sectors_per_cluster;
unsigned bytes_per_sector;
};
멤버의 이름에 의미가 잘 나타나 있으므로 별도의 설명은 필요치 않을 것 같다. 대용량의 디스크는 클러스터 단위로 파일을 기록하므로 모든 정보들도 클러스터 수로 되어 있다. 이 구조체의 멤버를 조사하면 디스크의 총 용량과 남은 용량을 알 수 있고 두 값의 차를 구하면 사용한 용량도 쉽게 계산할 수 있다. 다음 예제는 이 함수로 C 드라이브의 현재 상태를 조사하여 출력한다.
예 제 : diskfree
#include <Turboc.h>
#include <dos.h>
void main()
{
_diskfree_t df;
int bytes;
int total,avail;
_getdiskfree(3,&df);
bytes=df.sectors_per_cluster*df.bytes_per_sector;
total=MulDiv(df.total_clusters,bytes,1048576);
avail=MulDiv(df.avail_clusters,bytes,1048576);
printf("총 용량=%dM, 사용한 용량=%dM, 남은 용량=%dM, 클러스터당 바이트=%dB.\n",
total,total-avail,avail,bytes);
}
대용량 하드 디스크를 바이트 단위로 조사하면 정수형의 범위를 넘어 버리기 때문에 메가 바이트 단위로 값을 출력하도록 했다. MulDiv는 Win32 API 함수인데 대단히 큰 수를 곱한 후 나누기를 할 때 내부적으로 64비트 계산을 해 주어 자리 넘침에 의한 오차를 제거해 준다.
'Talk > IT' 카테고리의 다른 글
| Software Wars (2) | 2006/07/24 |
|---|---|
| Invalid Address specified to RtlFreeHeap (2) | 2006/07/21 |
| 파일 및 디렉토리 접근 함수 (0) | 2006/06/22 |
| htaccess를 이용한 폴더 접근 권한 설정 (0) | 2006/06/22 |
| DMA 설정 (0) | 2006/06/22 |
| 대용량 파일 업로드 가능하게 하는 방법 (0) | 2006/06/22 |
TAG c&cpp



