윈도우즈 시스템 프로그래밍이라는 책과 해당 책의 저자이신 윤성우님의 강의를 통해 공부한 내용을 정리하는 글입니다.
파일 열기 및 닫기
⦁ 파일을 열 때 사용하는 함수 CreateFile
HANDLE CreateFile (
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
// If this function fails, the return value is INVALID_HANLDE_VALUE.
⦁ lpFileName : 개방할 파일 이름을 지정한다.
⦁ dwDesiredAccess : 읽기/쓰기 모드를 지정한다. or 연산으로 결합 가능
- GENERIC_READ : 읽기 모드 지정
- GENERIC_WRITE : 쓰기 모드 지정
⦁ dwShareMode : 파일 공유 방식을 지정한다.
- 0 : 다른 프로세스에 공유 불가, 이미 개방된 파일은 중복 개방 불가 - FILE_SHARE_READ : 다른 프로세스에서 이 파일 동시 읽기 접근 가능 - FILE_SHARE_WRITE : 다른 프로세스에서 이 파일 동시 쓰기 접근 가능, 같은 영역에 동시에 데이터 쓰기 지양
⦁ lpSecurityAttributes : 보안 속성 지정. 디폴트는 NULL 전달
⦁ dwCreationDisposition : 파일이 생성되는 방법을 지정한다.
- CREATE_ALWAYS : 항상 새 파일을 생성한다.
- CREATE_NEW : 새 파일 생성, 같은 이름의 파일이 존재하면 생성 실패
- OPEN_ALWAYS : 기존 파일 개방, 없으면 새로 생성
- OPEN_EXISTING : 기존 파일 개방, 존재하지 않으면 함수 호출 실패
- TRUNCATE_EXISTING : 기존 파일의 내용 지우고 개방, 파일이 존재하지 않으면 호출 실패
⦁ dwFlagsAndAttributes : 파일의 특성 정보를 설정. 둘 이상의 특성 정보가 OR 연산자를 통해서 지정, 기본적으로 FILE_ATTRIBUTES_NORMAL이라는 값을 사용한다.
⦁ hTemplateFile : 기존에 존재하는 파일과 동일한 특성을 가지는 새 파일을 만들 때 사용되는 전달인자. Windows ME/98/95에서는 이 전달인자를 지원하지 않으므로 NULL을 전달한다.
⦁ 함수 호출이 성공하면, 파일의 핸들이 반환된다.
⦁ 파일을 종료할 때에는 CloseHandle을 사용하면 된다.
파일 읽기 & 쓰기와 포인터
⦁ 파일에 데이터를 읽을 때 사용하는 함수 ReadFile
BOOL ReadFile (
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
// If the function fails, the return value is zero.
⦁ hFile : 데이터를 읽을 파일의 핸들을 지정한다.
⦁ lpBuffer : 읽어 들인 데이터를 저장할 버퍼(배열, 메모리)의 주소(포인터)를 지정한다.
⦁ nNumberOfBytesToRead : 파일로부터 읽고자 하는 데이터의 크기를 바이트 단위로 지정한다.
⦁ lpNumberOfBytesRead : 실제 읽어 들인 데이터 크기를 얻기 위한 변수의 주소를 지정한다.
⦁ 파일에 데이터를 저장할 때 사용하는 함수 WriteFile
BOOL WriteFile (
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
// If the function fails, the return value is zero.
⦁ hFile : 데이터를 저장할 파일의 핸들 지정
⦁ lpBuffer : 데이터를 저장하고 있는 버퍼의 주소 지정
⦁ nNumberOfBytesToWrite : 파일에 저장하고자 하는 데이터 크기를 바이트 단위로 지정
⦁ lpNumberOfBytesWritten : 파일에 실제 저장된 데이터 크기를 얻기 위해 변수의 주소 지정
파일을 열어서 읽고 쓰고 닫는 예제
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
int _tmain(int argc, TCHAR* argv[])
{
TCHAR fileName[] = _T("data.txt");
TCHAR fileData[] = _T("Just test string~");
HANDLE hFile = CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("FIle creation fault! \n"));
return -1;
}
DWORD numOfBytesWritten = 0;
WriteFile(hFile, fileData, sizeof(fileData), &numOfBytesWritten, NULL);
_tprintf(_T("Written data size : %d \n"), numOfBytesWritten);
CloseHandle(hFile);
return 0;
}
위에서 만든 파일에 저장된 데이터를 읽어들이는 예제
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#define STRING_LEN 100
int _tmain(int argc, TCHAR* argv[])
{
TCHAR fileName[] = _T("data.txt");
TCHAR fileData[STRING_LEN];
HANDLE hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("File open fault! \n"));
return -1;
}
DWORD numOfByteRead = 0;
ReadFile(hFile, fileData, sizeof(fileData), &numOfByteRead, NULL);
fileData[numOfByteRead / sizeof(TCHAR)] = 0;
_tprintf(_T("Read data size : %u \n"), numOfByteRead);
_tprintf(_T("Read string : %s \n"), fileData);
}
파일의 시간 정보 얻어오기
파일 속성에서 확인할 수 있는 날짜 정보는 위와 같다.
프로그램에서 이와 같은 정보를 얻거나 변경하기 위해서는 아래 함수를 사용하면 된다.
⦁ GetFileTime
BOOL GetFileTime (
HANDLE hFile,
LPFILETIME lpCreationTime,
LPFILETIME lpLastAccessTime,
LPFILETIME lpLastWriteTime
);
//If the function fails, the return value is zero.
⦁ hFile : 시간 관련 정보를 얻을 대상 파일의 핸들 지정
⦁ lpCreationTime : 파일이 생성된 시간을 얻기 위해 FILETIME 구조체 변수의 주소값을 전달한다. NULL 전달 가능
⦁ lpLastAccessTime : 파일의 마지막 접근 시간을 얻기 위해 FILETIME 구조체 변수의 주소값을 전달한다. NULL 전달 가능
⦁ lpLastWriteTime : 파일의 마지막 데이터 갱신 시간을 얻기 위해 FILETIME 구조체 변수의 주소값 전달. NULL 전달 가능
FILETIME 구조는 아래와 같이 선언되어 있다.
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, * PFILETIME;
FILETIME 구조체는 시간 정보를 나타내는 8바이트 자료형(DWORD * 2)이다. 이 구조체는 UTC 기반으로 시간을 표현한다.
UTC란 세계 시간 기준을 만들기 위해 정의된 시간이다. 1601년 1월 1일을 기준으로 100 나노초 단위 기준으로 지나간 시간을 계산하는 것이다. 이는 알아보기 힘들기 때문에 우리가 원하는 스케일의 시간 정보로 바꿔줄 필요가 있다.
아래 예제에서 해당 함수의 사용법을 익힐 수 있다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#define STRING_LEN 100
int _tmain(int argc, TCHAR* argv[])
{
TCHAR fileName[] = _T("data.txt");
TCHAR fileCreationTimeInfo[STRING_LEN];
TCHAR fileAccessTimeInfo[STRING_LEN];
TCHAR fileWriteTimeInfo[STRING_LEN];
FILETIME ftCreate, ftAccess, ftWrite;
SYSTEMTIME stCreateUTC, stCreateLocal;
SYSTEMTIME stAccessUTC, stAccessLocal;
SYSTEMTIME stWriteUTC, stWriteLocal;
HANDLE hFile = CreateFile(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("File open fault! \n"));
return -1;
}
if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
{
_tprintf(_T("GetFileTime function call fault! \n"));
return FALSE;
}
FileTimeToSystemTime(&ftCreate, &stCreateUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stCreateUTC, &stCreateLocal);
FileTimeToSystemTime(&ftAccess, &stAccessUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stAccessUTC, &stAccessLocal);
FileTimeToSystemTime(&ftWrite, &stWriteUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stWriteUTC, &stWriteLocal);
_stprintf(fileCreationTimeInfo, _T("%02d/%02d/%d %02d:%02d"), stCreateLocal.wMonth, stCreateLocal.wDay, stCreateLocal.wYear, stCreateLocal.wHour, stCreateLocal.wMinute);
_stprintf(fileAccessTimeInfo, _T("%02d/%02d/%d %02d:%02d"), stAccessLocal.wMonth, stAccessLocal.wDay, stAccessLocal.wYear, stAccessLocal.wHour, stAccessLocal.wMinute);
_stprintf(fileWriteTimeInfo, _T("%02d/%02d/%d %02d:%02d"), stWriteLocal.wMonth, stAccessLocal.wDay, stAccessLocal.wYear, stAccessLocal.wHour, stAccessLocal.wMinute);
_tprintf(_T("File created time: %s \n"), fileCreationTimeInfo);
_tprintf(_T("File accessed time: %s \n"), fileAccessTimeInfo);
_tprintf(_T("File written time: %s \n"), fileWriteTimeInfo);
CloseHandle(hFile);
return 0;
}
FileTimeToSystemTime 함수의 호출로 Time Zone을 바꿔주는 것이 아닌 UTC 기준의 시간을 포맷만 바꾸어주는 것이므로 SystemTimeToTzSpecificLocalTime 함수를 호출해서 Time Zone을 바꿔줘야 한다.
파일 사이즈 얻어오기
⦁ 파일 크기를 계산하여 반환하는 함수 GetFileSize
DWORD GetFileSize (
HANDLE hFile,
LPDWORD lpFileSizeHigh
);
// If the function fails and lpFileSizeHigh is non-NULL, the return value is INVALID_FILE_SIZE
⦁ hFile : 전달된 핸들의 파일 크기를 얻게된다.
⦁ lpFileSizeHigh : 이 함수는 4바이트 DWORD로 반환형이 지정되어 있다. 따라서 4GB 이상의 파일 크기를 반환값으로 얻는 것은 불가능하다. 4GB 이상 되는 파일의 크기를 얻을 때 사용되는 것이 이 인자이다. 4GB가 넘는 파일의 상위 4바이트 정보를 얻을 수 있다.
GetFileSize 함수는 4GB 이상의 파일의 경우에 상위 4바이트, 하위 4바이트 정보를 따로 얻어야 한다. 이 불편함을 해결하기 위해 아래 함수 사용을 고려할 수 있다.
BOOL GetFileSizeEx (
HANDLE hFile,
PLARGE_INTEGER lpFileSize
);
//If the function fails, the return value is zero.
⦁ hFile : 파일의 핸들 전달
⦁ lpFileSize : 파일 크기를 저장하기 위한 변수의 주소값을 인자로 전달한다. LARGE_INTEGER는 8바이트 자료형이다.
⦁ PLARGE_INTEGER
typedef union _LARGE_INTEGER
{
struct {
DWORD LowPart;
LONG HighPart;
};
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
int _tmain(int argc, TCHAR* argv[])
{
TCHAR fileName[] = _T("data.txt");
HANDLE hFile = CreateFile(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("File open fault! \n"));
return -1;
}
DWORD high4ByteFileSize = 0;
DWORD low4ByteFileSize = GetFileSize(hFile, &high4ByteFileSize);
_tprintf(_T("High 4byte file size : %u byte\n"),high4ByteFileSize);
_tprintf(_T("Low 4byte file size : %u byte\n"), low4ByteFileSize);
LARGE_INTEGER fileSize;
GetFileSizeEx(hFile, &fileSize);
_tprintf(_T("Total file size: %u byte\n"), fileSize.QuadPart);
CloseHandle(hFile);
return 0;
}
실행결과
fileSize.QuadPart는 Union이므로 40 byte가 출력되었다.
파일의 특성 정보 가져오기
⦁ GetFileAttributes
DWORD GetFileAttributes (
LPCTSTR lpFileName
);
// If the function fails, the return value is INVALID_FILE_ATTRIBUTES.
⦁ lpFileName : 파일의 핸들을 전달
위 함수는 DWORD형의 반환값을 얻을 수 있는데, 여러 정보가 담겨있으므로 비트 단위로 의미가 부여되어 있다.
0번째 비트(0x00000001)가 1이면 읽기 전용 특성, 1번째 비트(0x00000002)가 1이면 숨김 특성이다.
각각 매크로 상수 FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_HIDDEN으로 정의되어 있다.
이 둘 외에도 여러 특성이 정의되어 있다.
⦁ SetFileAttributes
BOOL SetFileAttributes (
LPCCTSTR lpFileName,
DWORD dwFileAttributes
);
//If the function fails, the return value is zero.
⦁ lpFileName : 파일의 핸들 전달
⦁ dwFileAttributes : 변경할 특성 정보 전달
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
void ShowAttributes(DWORD attrib);
int _tmain(int argc, TCHAR* argv[])
{
TCHAR fileName[] = _T("data.txt");
_tprintf(_T("Original file attributes \n"));
DWORD attrib = GetFileAttributes(_T("data.txt"));
ShowAttributes(attrib);
attrib |= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
SetFileAttributes(_T("data.txt"), attrib);
_tprintf(_T("Changed file attributes \n"));
attrib = GetFileAttributes(_T("data.txt"));
ShowAttributes(attrib);
return 0;
}
void ShowAttributes(DWORD attrib)
{
if (attrib & FILE_ATTRIBUTE_NORMAL)
{
_tprintf(_T("Normal \n"));
}
else
{
if (attrib & FILE_ATTRIBUTE_READONLY)
_tprintf(_T("Read Only\n"));
if (attrib & FILE_ATTRIBUTE_HIDDEN)
_tprintf(_T("Hidden \n"));
}
_tprintf(_T("\n"));
}
위에서 소개한 두 함수는 파일 핸들을 필요로하지 않는다. 대신 파일 이름에 경로가 포함되어야 하므로 활용이 제한적이다.
파일의 특성 정보를 핸들로부터 얻어오기
⦁ 파일의 특성을 핸들을 통해 가져오는 함수 GetFileInformationByHandle
BOOL GetFileInformationByHandle (
HANDLE hFile,
LPBY_HANLDE_FILE_INFORMATION lpFileInformation
);
// If the function fails, the return value is zero.
⦁ hFile : 파일의 핸들 전달
⦁ LPBY_HANDLE_FILE_INFORMATION : 구조체 BY_HANDLE_FILE_INFORMATION의 포인터, 여기로 전달되는 주소의 변수에 파일 정보가 채워진다.
이 함수를 통해서 파일의 특성 정보, 시간 정보, 파일의 크기 정보를 비롯하여 추가적인 파일 시스템 정보도 얻을 수 있다.
typedef struct _BY_HANDLE_FILE_INFORMATION
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwVolmeSerialNumber;
DWORD nFileSizeHigh;
DWROD nFileSizeLow;
DWORD nNumberOfLinks;
DWORD nFileIndexHigh;
DWORD nFileIndexLow;
} BY_HANDLE_FILE_INFORMATION, *BY_HANDLE_FILE_INFORMATION;
파일의 경로 정보 얻어오기
⦁ GetFullPathName
DWORD GetFullPathName (
LPCTSTR lpFileName,
DWORD nBufferLength,
LPTSTR lpBuffer,
LPTSTR* lpFilePart
);
//If the function fails, the return value is zero.
⦁ lpFileName : 완전경로를 확인하고자 하는 파일 이름 전달
⦁ nBufferLength : 완전 경로를 저장할 버퍼에 저장 간으한 문자열 길이 지정
⦁ lpBuffer : 완전경로를 지정할 버퍼의 주소값 지정
⦁ lpFilePart : 완전경로가 문자열로 버퍼에 저장된 후, 버퍼의 특정 위치를 가리키는 포인터 값이 저장
'윈도우즈 시스템 프로그래밍' 카테고리의 다른 글
윈도우즈 시스템 프로그래밍 18장 - 비동기(Asynchronous) I/O (0) | 2021.08.18 |
---|---|
윈도우즈 시스템 프로그래밍 18장 - 디렉터리 관련 함수 및 그밖의 함수들 (0) | 2021.08.16 |
윈도우즈 시스템 프로그래밍 17장 - 예외 핸들러(Exception Handler) (0) | 2021.08.14 |
윈도우즈 시스템 프로그래밍 17장 - SEH(Structured Exception Handling) / 종료 핸들러(Termination Handler) (0) | 2021.08.12 |
윈도우즈 시스템 프로그래밍 16장 - 가상 메모리(Virtual Memory) (0) | 2021.08.08 |