Windows API 파일 I/O·레지스트리 | 파일 처리 완벽 가이드
이 글의 핵심
Windows에서 파일 처리는 CreateFile로 핸들을 얻고 ReadFile/WriteFile로 읽고 씁니다. 레지스트리는 RegOpenKeyEx로 키를 열고 RegQueryValueEx로 읽습니다. 파일 매핑으로 대용량 파일을 메모리처럼 처리할 수 있습니다.
들어가며
Windows 파일 시스템 API는 1990년대 Windows NT부터 제공된 강력한 파일 처리 인터페이스입니다. C 표준 라이브러리(fopen, fread)보다 저수준이지만, 비동기 I/O, 파일 잠금, 메모리 매핑 같은 고급 기능을 제공합니다.
// Windows API 파일 쓰기 기본
HANDLE hFile = CreateFile(L"test.txt", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
const char* data = "Hello, Windows!";
DWORD written;
WriteFile(hFile, data, (DWORD)strlen(data), &written, NULL);
CloseHandle(hFile);
레지스트리는 Windows의 중앙 설정 데이터베이스로, 애플리케이션 설정, 사용자 환경, 시스템 구성을 저장합니다.
1. 파일 열기와 닫기
1.1 CreateFile - 모든 것의 시작
HANDLE CreateFile(
LPCWSTR lpFileName, // 파일 경로
DWORD dwDesiredAccess, // 접근 권한
DWORD dwShareMode, // 공유 모드
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 보안 속성
DWORD dwCreationDisposition, // 생성 방식
DWORD dwFlagsAndAttributes, // 플래그와 속성
HANDLE hTemplateFile // 템플릿 파일 (보통 NULL)
);
// 읽기 전용으로 열기
HANDLE hFile = CreateFile(
L"C:\\data.txt",
GENERIC_READ, // 읽기
FILE_SHARE_READ, // 다른 프로세스도 읽기 가능
NULL, // 기본 보안
OPEN_EXISTING, // 파일이 있어야 함
FILE_ATTRIBUTE_NORMAL, // 일반 파일
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
wchar_t buf[256];
swprintf_s(buf, L"파일 열기 실패! 에러 코드: %d", err);
MessageBox(NULL, buf, L"오류", MB_ICONERROR);
return;
}
// 사용 후 반드시 닫기
CloseHandle(hFile);
1.2 CreateFile 파라미터 상세
// dwDesiredAccess (접근 권한)
GENERIC_READ // 읽기
GENERIC_WRITE // 쓰기
GENERIC_READ | GENERIC_WRITE // 읽기+쓰기
// dwShareMode (공유 모드)
0 // 독점 (다른 프로세스 접근 불가)
FILE_SHARE_READ // 다른 프로세스 읽기 허용
FILE_SHARE_WRITE // 다른 프로세스 쓰기 허용
FILE_SHARE_DELETE // 다른 프로세스 삭제 허용
FILE_SHARE_READ | FILE_SHARE_WRITE // 읽기+쓰기 허용
// dwCreationDisposition (생성 방식)
CREATE_NEW // 새 파일 생성 (이미 있으면 실패)
CREATE_ALWAYS // 항상 새 파일 생성 (덮어쓰기)
OPEN_EXISTING // 기존 파일 열기 (없으면 실패)
OPEN_ALWAYS // 있으면 열고, 없으면 생성
TRUNCATE_EXISTING // 기존 파일 열고 크기를 0으로
// dwFlagsAndAttributes (플래그와 속성)
FILE_ATTRIBUTE_NORMAL // 일반 파일
FILE_ATTRIBUTE_READONLY // 읽기 전용
FILE_ATTRIBUTE_HIDDEN // 숨김
FILE_FLAG_OVERLAPPED // 비동기 I/O
FILE_FLAG_NO_BUFFERING // 버퍼링 없음 (직접 I/O)
FILE_FLAG_SEQUENTIAL_SCAN // 순차 스캔 최적화
FILE_FLAG_RANDOM_ACCESS // 랜덤 액세스 최적화
1.3 파일 존재 확인
bool FileExists(const wchar_t* path)
{
DWORD attr = GetFileAttributes(path);
return (attr != INVALID_FILE_ATTRIBUTES &&
!(attr & FILE_ATTRIBUTE_DIRECTORY));
}
// 사용 예
if (FileExists(L"C:\\config.ini")) {
MessageBox(NULL, L"파일이 존재합니다.", L"알림", MB_OK);
}
2. 파일 읽기와 쓰기
2.1 ReadFile - 파일 읽기
// 텍스트 파일 읽기
HANDLE hFile = CreateFile(L"data.txt", GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
MessageBox(NULL, L"파일 열기 실패!", L"오류", MB_ICONERROR);
return;
}
// 파일 크기 얻기
LARGE_INTEGER fileSize;
GetFileSizeEx(hFile, &fileSize);
// 버퍼 할당
char* buffer = new char[(size_t)fileSize.QuadPart + 1];
// 읽기
DWORD bytesRead;
if (!ReadFile(hFile, buffer, (DWORD)fileSize.QuadPart, &bytesRead, NULL)) {
MessageBox(NULL, L"파일 읽기 실패!", L"오류", MB_ICONERROR);
delete[] buffer;
CloseHandle(hFile);
return;
}
buffer[bytesRead] = '\0'; // null terminator
// 사용
MessageBoxA(NULL, buffer, "파일 내용", MB_OK);
// 정리
delete[] buffer;
CloseHandle(hFile);
2.2 WriteFile - 파일 쓰기
// 텍스트 파일 쓰기
HANDLE hFile = CreateFile(L"output.txt", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
MessageBox(NULL, L"파일 생성 실패!", L"오류", MB_ICONERROR);
return;
}
const char* data = "Hello, Windows!\nLine 2\nLine 3";
DWORD bytesWritten;
if (!WriteFile(hFile, data, (DWORD)strlen(data), &bytesWritten, NULL)) {
MessageBox(NULL, L"파일 쓰기 실패!", L"오류", MB_ICONERROR);
CloseHandle(hFile);
return;
}
CloseHandle(hFile);
wchar_t buf[256];
swprintf_s(buf, L"%d 바이트 기록됨", bytesWritten);
MessageBox(NULL, buf, L"완료", MB_OK);
2.3 유니코드 파일 처리
// UTF-16 (유니코드) 파일 쓰기
HANDLE hFile = CreateFile(L"unicode.txt", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// BOM (Byte Order Mark) 쓰기
WORD bom = 0xFEFF;
DWORD written;
WriteFile(hFile, &bom, sizeof(WORD), &written, NULL);
// 유니코드 문자열 쓰기
const wchar_t* text = L"안녕하세요, 세계!\nHello, World!";
WriteFile(hFile, text, (DWORD)(wcslen(text) * sizeof(wchar_t)), &written, NULL);
CloseHandle(hFile);
2.4 파일 포인터 이동
HANDLE hFile = CreateFile(L"data.bin", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// 파일 처음으로
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
// 파일 끝으로
SetFilePointer(hFile, 0, NULL, FILE_END);
// 상대 위치 (현재 위치에서 100바이트 앞으로)
SetFilePointer(hFile, 100, NULL, FILE_CURRENT);
// 현재 위치 얻기
DWORD pos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
// 대용량 파일 (64비트)
LARGE_INTEGER distance;
distance.QuadPart = 1000000000LL; // 1GB
SetFilePointerEx(hFile, distance, NULL, FILE_BEGIN);
CloseHandle(hFile);
3. 파일 정보와 속성
3.1 파일 정보 얻기
HANDLE hFile = CreateFile(L"data.txt", GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
BY_HANDLE_FILE_INFORMATION fileInfo;
if (GetFileInformationByHandle(hFile, &fileInfo)) {
wchar_t buf[1024];
swprintf_s(buf,
L"파일 크기: %u 바이트\n"
L"생성 시간: %08X %08X\n"
L"수정 시간: %08X %08X\n"
L"속성: %08X",
fileInfo.nFileSizeLow,
fileInfo.ftCreationTime.dwHighDateTime,
fileInfo.ftCreationTime.dwLowDateTime,
fileInfo.ftLastWriteTime.dwHighDateTime,
fileInfo.ftLastWriteTime.dwLowDateTime,
fileInfo.dwFileAttributes
);
MessageBox(NULL, buf, L"파일 정보", MB_OK);
}
CloseHandle(hFile);
3.2 파일 시간 변환
// FILETIME을 SYSTEMTIME으로 변환
BY_HANDLE_FILE_INFORMATION fileInfo;
GetFileInformationByHandle(hFile, &fileInfo);
SYSTEMTIME st;
FileTimeToSystemTime(&fileInfo.ftLastWriteTime, &st);
wchar_t buf[256];
swprintf_s(buf, L"수정 시간: %04d-%02d-%02d %02d:%02d:%02d",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond);
MessageBox(NULL, buf, L"시간", MB_OK);
// 로컬 시간으로 변환
FILETIME ftLocal;
FileTimeToLocalFileTime(&fileInfo.ftLastWriteTime, &ftLocal);
FileTimeToSystemTime(&ftLocal, &st);
swprintf_s(buf, L"로컬 시간: %04d-%02d-%02d %02d:%02d:%02d",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond);
MessageBox(NULL, buf, L"로컬 시간", MB_OK);
3.3 파일 속성 변경
// 읽기 전용 설정
SetFileAttributes(L"data.txt", FILE_ATTRIBUTE_READONLY);
// 숨김 파일 설정
SetFileAttributes(L"secret.dat", FILE_ATTRIBUTE_HIDDEN);
// 여러 속성 조합
SetFileAttributes(L"important.txt",
FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
// 속성 읽기
DWORD attr = GetFileAttributes(L"data.txt");
if (attr != INVALID_FILE_ATTRIBUTES) {
if (attr & FILE_ATTRIBUTE_READONLY) {
MessageBox(NULL, L"읽기 전용 파일입니다.", L"알림", MB_OK);
}
}
4. 디렉토리 작업
4.1 디렉토리 생성과 삭제
// 디렉토리 생성
if (CreateDirectory(L"C:\\MyFolder", NULL)) {
MessageBox(NULL, L"폴더 생성 성공!", L"알림", MB_OK);
} else {
DWORD err = GetLastError();
if (err == ERROR_ALREADY_EXISTS) {
MessageBox(NULL, L"폴더가 이미 존재합니다.", L"알림", MB_OK);
} else {
MessageBox(NULL, L"폴더 생성 실패!", L"오류", MB_ICONERROR);
}
}
// 디렉토리 삭제 (비어있어야 함)
if (RemoveDirectory(L"C:\\MyFolder")) {
MessageBox(NULL, L"폴더 삭제 성공!", L"알림", MB_OK);
} else {
MessageBox(NULL, L"폴더 삭제 실패! (비어있지 않음?)", L"오류", MB_ICONERROR);
}
4.2 디렉토리 탐색
#include <vector>
#include <string>
std::vector<std::wstring> ListFiles(const wchar_t* directory)
{
std::vector<std::wstring> files;
wchar_t searchPath[MAX_PATH];
swprintf_s(searchPath, L"%s\\*", directory);
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
return files;
}
do {
// "."와 ".." 제외
if (wcscmp(findData.cFileName, L".") != 0 &&
wcscmp(findData.cFileName, L"..") != 0) {
files.push_back(findData.cFileName);
// 디렉토리 여부 확인
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// 디렉토리
} else {
// 파일
}
}
} while (FindNextFile(hFind, &findData));
FindClose(hFind);
return files;
}
// 사용 예
std::vector<std::wstring> files = ListFiles(L"C:\\Windows");
std::wstring list;
for (const auto& file : files) {
list += file + L"\n";
}
MessageBox(NULL, list.c_str(), L"파일 목록", MB_OK);
4.3 재귀적 디렉토리 탐색
void ListFilesRecursive(const wchar_t* directory, std::vector<std::wstring>& files)
{
wchar_t searchPath[MAX_PATH];
swprintf_s(searchPath, L"%s\\*", directory);
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) return;
do {
if (wcscmp(findData.cFileName, L".") != 0 &&
wcscmp(findData.cFileName, L"..") != 0) {
wchar_t fullPath[MAX_PATH];
swprintf_s(fullPath, L"%s\\%s", directory, findData.cFileName);
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// 서브 디렉토리 탐색
ListFilesRecursive(fullPath, files);
} else {
// 파일 추가
files.push_back(fullPath);
}
}
} while (FindNextFile(hFind, &findData));
FindClose(hFind);
}
5. 파일 매핑 (Memory-Mapped Files)
5.1 기본 파일 매핑
// 파일 열기
HANDLE hFile = CreateFile(L"large.dat", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// 파일 매핑 객체 생성
HANDLE hMapping = CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE, // 읽기+쓰기
0, // 최대 크기 (상위 32비트)
0, // 최대 크기 (하위 32비트, 0 = 파일 크기)
NULL // 이름 (NULL = 익명)
);
if (hMapping == NULL) {
CloseHandle(hFile);
return;
}
// 메모리에 매핑
void* pView = MapViewOfFile(
hMapping,
FILE_MAP_ALL_ACCESS, // 접근 권한
0, // 오프셋 (상위 32비트)
0, // 오프셋 (하위 32비트)
0 // 크기 (0 = 전체)
);
if (pView == NULL) {
CloseHandle(hMapping);
CloseHandle(hFile);
return;
}
// 메모리처럼 사용!
char* data = (char*)pView;
data[0] = 'A'; // 파일의 첫 바이트 수정
// 정리
UnmapViewOfFile(pView);
CloseHandle(hMapping);
CloseHandle(hFile);
5.2 프로세스 간 공유 메모리
// 프로세스 A (생성자)
HANDLE hMapping = CreateFileMapping(
INVALID_HANDLE_VALUE, // 파일 없음 (메모리만)
NULL,
PAGE_READWRITE,
0,
4096, // 4KB
L"MySharedMemory" // ★ 이름 지정
);
void* pView = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
// 데이터 쓰기
strcpy_s((char*)pView, 4096, "Hello from Process A!");
// ... 프로세스 A 계속 실행
UnmapViewOfFile(pView);
CloseHandle(hMapping);
// 프로세스 B (읽기)
HANDLE hMapping = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
FALSE,
L"MySharedMemory" // ★ 같은 이름
);
if (hMapping == NULL) {
MessageBox(NULL, L"공유 메모리 열기 실패!", L"오류", MB_ICONERROR);
return;
}
void* pView = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
// 데이터 읽기
MessageBoxA(NULL, (char*)pView, "Process B", MB_OK);
UnmapViewOfFile(pView);
CloseHandle(hMapping);
6. 레지스트리 (Registry)
6.1 레지스트리 읽기
// HKEY_CURRENT_USER\Software\MyApp\Settings\UserName 읽기
HKEY hKey;
LONG result = RegOpenKeyEx(
HKEY_CURRENT_USER,
L"Software\\MyApp\\Settings",
0,
KEY_READ,
&hKey
);
if (result != ERROR_SUCCESS) {
MessageBox(NULL, L"레지스트리 키 열기 실패!", L"오류", MB_ICONERROR);
return;
}
wchar_t userName[256];
DWORD dataSize = sizeof(userName);
DWORD dataType;
result = RegQueryValueEx(
hKey,
L"UserName",
NULL,
&dataType,
(LPBYTE)userName,
&dataSize
);
if (result == ERROR_SUCCESS && dataType == REG_SZ) {
MessageBox(NULL, userName, L"사용자 이름", MB_OK);
} else {
MessageBox(NULL, L"값 읽기 실패!", L"오류", MB_ICONERROR);
}
RegCloseKey(hKey);
6.2 레지스트리 쓰기
// HKEY_CURRENT_USER\Software\MyApp\Settings 키 생성
HKEY hKey;
DWORD disposition;
LONG result = RegCreateKeyEx(
HKEY_CURRENT_USER,
L"Software\\MyApp\\Settings",
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&disposition
);
if (result != ERROR_SUCCESS) {
MessageBox(NULL, L"레지스트리 키 생성 실패!", L"오류", MB_ICONERROR);
return;
}
if (disposition == REG_CREATED_NEW_KEY) {
MessageBox(NULL, L"새 키 생성됨", L"알림", MB_OK);
} else if (disposition == REG_OPENED_EXISTING_KEY) {
MessageBox(NULL, L"기존 키 열림", L"알림", MB_OK);
}
// 문자열 값 쓰기
const wchar_t* userName = L"홍길동";
RegSetValueEx(
hKey,
L"UserName",
0,
REG_SZ,
(LPBYTE)userName,
(DWORD)((wcslen(userName) + 1) * sizeof(wchar_t))
);
// 정수 값 쓰기
DWORD age = 30;
RegSetValueEx(
hKey,
L"Age",
0,
REG_DWORD,
(LPBYTE)&age,
sizeof(DWORD)
);
RegCloseKey(hKey);
6.3 레지스트리 삭제
// 값 삭제
HKEY hKey;
RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\MyApp\\Settings", 0, KEY_WRITE, &hKey);
RegDeleteValue(hKey, L"UserName");
RegCloseKey(hKey);
// 키 삭제 (비어있어야 함)
RegDeleteKey(HKEY_CURRENT_USER, L"Software\\MyApp\\Settings");
// 키 및 하위 키 모두 삭제 (Windows Vista+)
RegDeleteTree(HKEY_CURRENT_USER, L"Software\\MyApp");
6.4 레지스트리 열거
HKEY hKey;
RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\MyApp\\Settings", 0, KEY_READ, &hKey);
// 값 개수와 하위 키 개수 얻기
DWORD numValues, numSubKeys;
RegQueryInfoKey(hKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL,
&numValues, NULL, NULL, NULL, NULL);
wchar_t valueName[256];
DWORD valueNameSize;
DWORD dataType;
BYTE data[1024];
DWORD dataSize;
std::wstring list;
// 모든 값 열거
for (DWORD i = 0; i < numValues; i++) {
valueNameSize = 256;
dataSize = sizeof(data);
if (RegEnumValue(hKey, i, valueName, &valueNameSize, NULL,
&dataType, data, &dataSize) == ERROR_SUCCESS) {
wchar_t buf[512];
if (dataType == REG_SZ) {
swprintf_s(buf, L"%s = %s\n", valueName, (wchar_t*)data);
} else if (dataType == REG_DWORD) {
swprintf_s(buf, L"%s = %u\n", valueName, *(DWORD*)data);
}
list += buf;
}
}
MessageBox(NULL, list.c_str(), L"레지스트리 값들", MB_OK);
RegCloseKey(hKey);
7. INI 파일
7.1 INI 파일 읽기/쓰기
// config.ini 파일 쓰기
WritePrivateProfileString(
L"Settings", // 섹션
L"UserName", // 키
L"홍길동", // 값
L"C:\\config.ini" // 파일 경로
);
WritePrivateProfileInt(
L"Settings",
L"Age",
30,
L"C:\\config.ini"
);
// config.ini 파일 읽기
wchar_t userName[256];
GetPrivateProfileString(
L"Settings",
L"UserName",
L"기본값", // 기본값 (키가 없을 때)
userName,
256,
L"C:\\config.ini"
);
int age = GetPrivateProfileInt(
L"Settings",
L"Age",
0, // 기본값
L"C:\\config.ini"
);
wchar_t buf[512];
swprintf_s(buf, L"이름: %s\n나이: %d", userName, age);
MessageBox(NULL, buf, L"INI 파일", MB_OK);
7.2 INI 섹션 열거
// 모든 섹션 이름 얻기
wchar_t sections[4096];
GetPrivateProfileSectionNames(sections, 4096, L"C:\\config.ini");
// NULL로 구분된 문자열 파싱
std::wstring list;
const wchar_t* p = sections;
while (*p) {
list += p;
list += L"\n";
p += wcslen(p) + 1;
}
MessageBox(NULL, list.c_str(), L"섹션 목록", MB_OK);
8. 실전 예제: 로그 파일 관리자
#include <windows.h>
#include <string>
#include <ctime>
class Logger {
private:
HANDLE m_hFile;
CRITICAL_SECTION m_cs;
public:
Logger(const wchar_t* filename) {
m_hFile = CreateFile(
filename,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (m_hFile != INVALID_HANDLE_VALUE) {
// 파일 끝으로 이동 (추가 모드)
SetFilePointer(m_hFile, 0, NULL, FILE_END);
}
InitializeCriticalSection(&m_cs);
}
~Logger() {
if (m_hFile != INVALID_HANDLE_VALUE) {
CloseHandle(m_hFile);
}
DeleteCriticalSection(&m_cs);
}
void Log(const char* level, const char* message) {
if (m_hFile == INVALID_HANDLE_VALUE) return;
EnterCriticalSection(&m_cs);
// 타임스탬프
time_t now = time(NULL);
struct tm timeinfo;
localtime_s(&timeinfo, &now);
char timestamp[64];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &timeinfo);
// 로그 형식: [TIMESTAMP] [LEVEL] MESSAGE\n
char logLine[1024];
sprintf_s(logLine, "[%s] [%s] %s\r\n", timestamp, level, message);
DWORD written;
WriteFile(m_hFile, logLine, (DWORD)strlen(logLine), &written, NULL);
LeaveCriticalSection(&m_cs);
}
void Info(const char* message) { Log("INFO", message); }
void Warning(const char* message) { Log("WARN", message); }
void Error(const char* message) { Log("ERROR", message); }
};
// 사용 예
Logger logger(L"C:\\app.log");
logger.Info("Application started");
logger.Warning("Low memory warning");
logger.Error("Failed to connect to server");
logger.Info("Application terminated");
9. 실전 예제: 설정 관리 클래스
class Config {
private:
std::wstring m_iniPath;
public:
Config(const wchar_t* iniPath) : m_iniPath(iniPath) {}
// 문자열 읽기
std::wstring GetString(const wchar_t* section, const wchar_t* key,
const wchar_t* defaultValue = L"") {
wchar_t buf[1024];
GetPrivateProfileString(section, key, defaultValue, buf, 1024, m_iniPath.c_str());
return buf;
}
// 정수 읽기
int GetInt(const wchar_t* section, const wchar_t* key, int defaultValue = 0) {
return GetPrivateProfileInt(section, key, defaultValue, m_iniPath.c_str());
}
// 불린 읽기
bool GetBool(const wchar_t* section, const wchar_t* key, bool defaultValue = false) {
return GetInt(section, key, defaultValue ? 1 : 0) != 0;
}
// 문자열 쓰기
void SetString(const wchar_t* section, const wchar_t* key, const wchar_t* value) {
WritePrivateProfileString(section, key, value, m_iniPath.c_str());
}
// 정수 쓰기
void SetInt(const wchar_t* section, const wchar_t* key, int value) {
wchar_t buf[32];
swprintf_s(buf, L"%d", value);
WritePrivateProfileString(section, key, buf, m_iniPath.c_str());
}
// 불린 쓰기
void SetBool(const wchar_t* section, const wchar_t* key, bool value) {
SetInt(section, key, value ? 1 : 0);
}
};
// 사용 예
Config config(L"C:\\app.ini");
// 읽기
std::wstring userName = config.GetString(L"User", L"Name", L"Guest");
int volume = config.GetInt(L"Audio", L"Volume", 50);
bool autoSave = config.GetBool(L"Options", L"AutoSave", true);
// 쓰기
config.SetString(L"User", L"Name", L"홍길동");
config.SetInt(L"Audio", L"Volume", 75);
config.SetBool(L"Options", L"AutoSave", false);
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- Windows API 기초 | 메시지 루프와 윈도우 프로시저 완벽 가이드
- Windows API 컨트롤 | 버튼·에디트·리스트박스 완벽 가이드
- C++ 스마트 포인터 | unique_ptr/shared_ptr 메모리 안전 가이드
이 글이 도움이 되셨나요? Windows 파일 I/O와 레지스트리를 마스터하는 데 도움이 되었기를 바랍니다!
다음 글에서는 Windows API 멀티스레딩을 다루겠습니다. 🧵