01. 기본적인 파일 처리 함수들
우리는 ANSI 표준 파일 관련 함수들을 이미 알고 있다. 그러나, Windows에서 제공하는 파일 입/출력 관련 함수들은 다양한 기능을 제공하기 때문에 알 필요가 있다.
하지만, 단순히 파일에 데이터를 read/write 하는 것이 전부라면, ANSI 표준 함수가 호환성이 더 좋다.
파일 열기 & 닫기
파일을 개방(Open)하기 위해서 다음 함수를 사용한다.
HANDLE CreateFile(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
각 인자들은 Open 할 파일의 이름과 읽기/쓰기 모드를 정하는 등의 역할을 담당한다. 또한, 이 함수는 핸들을 반환하기 때문에, 파일을 종료할 때에는 커널 오브젝트의 핸들과 마찬가지로 CloseHandle 함수를 호출하면 된다.
파일 읽기 & 쓰기와 포인터
파일에 데이터를 읽을 때에는 다음 함수를 사용한다.
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
각 인자들은 데이터를 읽을 파일의 핸들을 넘겨주는 등의 역할을 한다.
반대로, 파일을 데이터를 저장할 때에는 다음 함수를 사용한다.
BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
마찬가지로, 각 인자들은 데이터를 저장할 파일의 핸들을 넘겨주는 등의 역할을 한다.
파일의 시간 정보 얻어오기
Windows에서는 다음과 같이 파일 정보의 확인이 가능하다.
이때 시간과 관련된 정보는 다음과 같다.
- 만든 날짜
- 수정한 날짜
- 액세스 한 날짜
프로그램상에서 위와 같은 정보를 얻기 위해 다음 함수를 사용한다.
BOOL GetFileTime(
HANDLE hFile,
LPFILETIME lpCreationTime,
LPFILETIME lpLastAccessTime,
LPFILETIME lpLastWriteTime
);
첫 번째 인자는 시간 관련 정보를 얻을 대상 파일의 핸들을 지정하며, 두 번째 인자는 파일의 생성 날짜를, 세 번째 인자는 마지막 접근 시간을, 네 번째 인자는 파일의 마지막 데이터 갱신 시간을 얻기 위한 FILETIME 구조체 변수의 주소값을 전달한다.
이때, FILETIME 구조체는 다음과 같이 정의되어 있다.
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, * PFILETIME, * LPFILETIME;
해당 구조체를 정리하면 다음과 같다.
“FILETIME 구조체는 시간 정보를 나타내는 8바이트 자료형으로, UTC 기반으로 시간을 표현한다.”
이때 UTC 기반 시간이란, 나라마다 제각각인 시간을 표준화하기 위한 국제 표준시이다.
또한, 우리가 원하는 타입으로 시간 정보를 변경하기 위해 다음 함수를 사용한다.
BOOL FileTimeToSystemTime(
FILETIME* lpFileTime,
LPSYSTEMTIME lpSystemTime
);
BOOL SystemTimeToTzSpecificLocalTime(
TIME_ZONE_INFORMATION* lpTimeZoneInformation,
SYSTEMTIME* lpUniversalTime,
LPSYSTEMTIME lpLocalTime
);
위에서 FileTimeToSystemTime 함수로 포맷을 변경시키지만, 여전히 UTC 기준이다. 이어서 SystemTimeToTzSpecificLocalTime 함수를 통해 UTC를 지정한 지역별, 국가별 시간대로 변경한다.
파일 사이즈 얻어오기
ANSI 표준 함수에서는 다음과 같이 파일 사이즈를 얻어 온다.
FILE* fp = fopen("test.dat", "rb");
fseek(fp, 0, SEEK_END);
DWORD sizeOfFile = ftell(fp);
이 과정은 fseek 함수를 통해 포인터를 끝으로 이동시킨 다음, ftell 함수를 호출해서 현재 위치 정보를 얻어 온다. 이때 파일 포인터를 끝으로 이동시켰기 때문에 현재 위치 정보는 파일 크기가 되는 것이다.
그러나, Windows 시스템에서는 직접 파일 크기를 계산해서 반환하는 함수를 제공한다.
DWORD GetFileSize(
HANDLE hFile,
LPDWORD lpFileSizeHigh
);
위의 함수는 반환형이 4바이트 DWORD이기 때문에, 4G 바이트 이상의 파일 크기를 반환값으로 얻는 것은 불가능하다. 이때 두 번째 인자가 사용된다. 이를 통해 4G바이트를 넘는 파일의 상위 4바이트 정보를 얻는다.
위에서 알 수 있듯이, GetFileSizesms 상위 4G 바이트와 하위 4G 바이트를 각각 다른 경로를 통해 얻어야 한다. 이러한 불편함이 싫다면 다음 함수를 사용할 수 있다.
BOOL GetFileSizeEx(
HANDLE hFile,
PLARGE_INTEGER lpFileSize
);
이는 Windows XP 버전 이상에서만 지원되는 함수이다.
파일의 특성(Attribute) 정보 얻어오기
앞서 확인했던 파일의 정보에서는 특성 또한 확인 가능하다. 이러한 특성 정보는 프로그램 코드상에서 변경 및 확인이 가능하다. 이때 다음 두 함수를 사용한다.
DWORD GetFileAttributes(
LPCWSTR lpFileName
);
위 함수의 호출을 통해 DWORD형 반환값을 얻을 수 있다. 이 안에 특성에 대한 정보들이 모두 들어있기 때문에 비트 단위로 의미가 부여되어 있다. 첫 번째 비트는 “읽기 전용 특성”을, 두 번째 비트는 “숨김 특성”을 표현한다.
또한, 다음 함수를 이용해 특성을 설정할 수 있다.
BOOL SetFileAttributes(
LPCWSTR lpFileName,
DWORD dwFileAttributes
);
위의 두 함수는 파일 핸들을 필요로 하지 않는다. 대신 위치 경로를 포함하는 파일의 이름을 필요로 한다. 이는 개발자에게 여러 가지 제약을 가져다준다.
파일의 특성(Attribute) 정보 핸들로부터 얻어오기
핸들을 이용해 파일 정보를 얻기 위해 사용되는 함수는 다음과 같다.
BOOL GetFileInformationByHandle(
HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);
해당 함수의 두 번째 인자 BY_HANDLE_FILE_INFORMATION 구조체에 파일 정보가 채워진다.
이때 BY_HANDLE_FILE_INFORMATION 구조체는 다음과 같다.
typedef struct _BY_HANDLE_FILE_INFORMATION {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwVolumeSerialNumber;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD nNumberOfLinks;
DWORD nFileIndexHigh;
DWORD nFileIndexLow;
} BY_HANDLE_FILE_INFORMATION, * PBY_HANDLE_FILE_INFORMATION, * LPBY_HANDLE_FILE_INFORMATION;
파일의 경로(Path) 정보 얻어오기
파일 이름을 통해서 파일 경로(Path) 정보를 얻기 위해 사용하는 함수는 다음과 같다.
DWORD GetFullPathName(
LPCSTR lpFileName,
DWORD nBufferLength,
LPSTR lpBuffer,
LPSTR* lpFilePart
);
파일 포인터의 이동 - 32비트 기반
ANSI 표준 함수 fseek에 해당하는 Windows 시스템 함수는 다음과 같다.
DWORD SetFilePointer(
HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod
);
추가적으로, 위의 함수가 실제로 지원하는 파일의 최대 크기는 2^32 - 2바이트 크기의 파일이다.
02. 디렉터리 관련 함수 및 그 밖의 함수들
디렉터리의 생성과 소멸
다음은 디렉터리를 생성 및 소멸하기 위해 사용하는 함수들이다.
BOOL CreateDirectory(
LPCWSTR lpPathName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
BOOL RemoveDirectory(
LPCWSTR lpPathName
);
현재 디렉터리, 시스템 디렉터리 그리고 Windows 디렉터리
다음은 MSDN을 참조하다 보면 간혹 등장하는 디렉터리 관련 용어들이다.
현재 디렉터리
프로그램이 Load된 디렉터리이며, 이후 변경 가능하다.
다음은 현재 디렉터리를 참조하거나 변경하는 데 사용하는 함수들이다.
DWORD GetCurrentDirectory(
DWORD nBufferLength,
LPWSTR lpBuffer
);
BOOL SetCurrentDirectory(
LPCWSTR lpPathName
);
시스템 디렉터리 & Windows 디렉터리
시스템 디렉터리는 각종 라이브러리(DLL) 및 드라이버 파일처럼 Windows 시스템에 중요한 파일들이 존재하는 위치이고, windows 디렉터리는 초기화 및 실행파일들이 존재하는 위치이다. 또한, 이들은 현재 디렉터리와 달리 변경이 불가능하다.
다음은 시스템 디렉터리와 Windows 디렉터리의 위치 정보를 확인하는 함수들이다.
UINT GetSystemDirectory(
LPWSTR lpBuffer,
UINT uSize
);
UINT GetWindowsDirectory(
LPWSTR lpBuffer,
UINT uSize
);
디렉터리에서 파일 찾기
파일의 위치 정보를 얻고자 할 때, 특정 디렉터리 내에 존재하는 파일 정보를 얻고자 할 때 사용하는 함수들은 다음과 같다. 다음은 문자열로 지정한 경로에 특정 파일이 존재하는지 확인하는 용도로 사용하는 함수이다.
DWORD SearchPath(
LPCWSTR lpPath,
LPCWSTR lpFileName,
LPCWSTR lpExtension,
DWORD nBufferLength,
LPWSTR lpBuffer,
LPWSTR* lpFilePart
);
참고 자료:
윤성우. 『뇌를 자극하는 윈도우즈 시스템 프로그래밍』.한빛미디어, 2007.
'독서 > [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]' 카테고리의 다른 글
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 17. 구조적 예외처리(SEH) 기법 (1) | 2023.12.12 |
---|---|
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 16. 컴퓨터 구조에 대한 네 번째 이야기 (2) | 2023.11.12 |
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 15. 쓰레드 풀링(Pooling) (1) | 2023.11.11 |
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 14. 쓰레드 동기화 기법 2 (2) | 2023.11.06 |
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 13. 쓰레드 동기화 기법 1 (2) | 2023.11.05 |