관리 메뉴

ㄴrㅎnㅂrㄹrㄱi

[강좌 18] 파일과 디렉토리 본문

API 관련/API 강좌모음

[강좌 18] 파일과 디렉토리

님투 2007. 10. 26. 03:42
반응형

[API]강좌(18)<--파일과디렉토리1



파일과 디렉토리를 다루어 보도록 하겠습니다. 모든 운영체제를
처음 배울때 바로 나오는 것이 바로 이 파일과 디렉토리에 관련된 것이라는 것을
여러분들은 잘 알것입니다. 그만큼 가장 기본이 되는거죠. 실제로 프로그램을
작성할때 가장 많이 사용하는 것이 구조체와 문자열 다루기, 그리고 바로 이 파일
입출력인데 윈도우즈에서도 파일 입출력이나, 디렉토리 다루는 것은 상당히 중요
합니다. 왜냐하면 프로그램을 만들고 실제로 인스톨하는 프로그램이나 언인스톨
프로그램을 만들때 이것에 대한 이해가 없다면 구현을 하지 못하기 때문이죠.
하긴 요즘에는 인스톨이나 언인스톨 프로그램을 직접 만들지 않고 툴을 이용해서
구현하는 경우가 많기 때문에 필요하지 않을수도 있습니다. 그러나 개성있는 프로
그램을 만들기 위해서는 어느정도 알아두면 좋을거라는 생각도 드는군요. 그러면
먼저 파일 입출력부터 알아 보겠습니다.
아마 비트맵 부분을 설명드릴때 이미 파일 입출력 부분을 제가 설명 드렸을 겁니
다. 먼저 그 방법을 다시 복습해 보도록 하겠습니다. 먼저 파일을 생성하는 방법
부터 알아 봅시다.

HFILE _lcreat(
LPCSTR lpszFileName,
int fnAttribute
)
;

위 함수를 이용해서 파일을 생성할수 있는데 첫번째 파라미터에 생성될 파일이름
을 지정하면 됩니다. 그리고 두번째 파라미터에 다음과 같은 값을 지정하여 그 속
성을 정의할수 있습니다.
0 일반적인 파일을 생성합니다.
1 읽기 전용 파일을 생성합니다.
2 히든 파일을 생성합니다.
4 시스템 파일을 생성합니다.
파일을 생성하는 과정은 파일에 어떠한 정보를 쓸때 사용하는 것입니다. 먼저 생성
한 후에 파일을 열고 쓰면 되죠. 만약에 파일에서 어떠한 정보를 읽어야 한다면
생성하는 과정을 할 필요는 없습니다. 그냥 파일을 열면 되는거죠. 그러면 파일을
어떻게 여는지 알아 봅시다.

HFILE _lopen(
LPCSTR lpszFileName,
int fnOpenMode
);

위 함수를 이용해서 존재하는 파일을 열수 있습니다. 첫번째 파라미터로 열 파일
이름을 지정해 주면 되고 두번쩨 파라미터에는 파일 접근 방식을 예약어로 지정
해주면 됩니다. 이 예약어로는 다음과 같은 것들이 올수 있습니다.
OF_READ 읽기 전용으로 파일을 엽니다.
OF_READWRITE 읽기 쓰기 전용으로 파일을 엽니다.
OF_WRITE 쓰기 전용으로 파일을 엽니다.
OF_SHARE_COMPAT 동시에 여러 프로그램에서 이 파일을 열수 있도록 합니다.
OF_SHARE_DENY_READ 다른 프로그램이 이 파일을 읽을수 있는 것을 금지시킵니다.
OF_SHARE_DENY_WRITE 다른 프로그램이 이 파일에 쓰는 것을 금지시킵니다.
OF_SHARE_EXCLUSIVE 다른 프로그램이 이 파일을 읽고 쓰는 것을 금지시킵니다.
파일을 여는 과정을 알았으니 파일을 닫는 방법도 알아 봅시다. 파일을 열어서 읽
거나 쓰는 과정이 끝나면 파일을 닫아 주어야 하는데 이때에는 아래 함수를 이용해
서 하면 됩니다.

HFILE _lclose(
HFILE hFile
);

첫번째 파라미터로 파일을 연 핸들을 지정해 주면 됩니다. 자 그러면 실제로 읽거
나 쓸때 어떤 함수를 이용해서 할수 있는지 봅시다.

UINT _lread(
HFILE hFile,
LPVOID lpBuffer,
UINT cbRead
)
;

파일에서 어떠한 정보를 읽어오고자 할때에는 위 함수를 이용해서 하면 됩니다. 첫
번째 파라미터에 파일을 열었을때 얻은 파일 핸들을 지정하면 되고 두번째 파라미
터에 정보를 저장할 버퍼를 세번째 파라미터에 버퍼 크기를 지정하면 됩니다.

UINT _lwrite(
HFILE hFile,
LPCSTR lpBuffer,
UINT cbWrite
);

파일에 정보를 기록할때에는 위 함수를 이용해서 하면 됩니다. 첫번째 파라미터는
역시 파일의 핸들을 지정하면 되고 두번째 파라미터는 정보를 세번재 파라미터에
는 정보의 크기를 지정해 주면 됩니다.
이미 앞에서 해본것들이라서 그렇게 크게 어려운 점은 없을 겁니다. 그러면이것을
이용한 실제 프로그램을 만들어 봅시다.

MyMenu MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Save", 100
MENUITEM "&Load", 200
END
END
#include <windows.h>
#include <string.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void SaveProc(void);
void LoadProc(void);
char GetHeader(void);
LPSTR GetData(void);
typedef struct tagMYFILE
{
char cHeader;
char szData[80];
} MYFILE;
MYFILE MyFile;
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
static char szAppName[] = "File & Directory Example";
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW|CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = "MyMenu";
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass))
return FALSE;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCTps;
static char cHeader;
static char szData[80];
switch(message)
{
case WM_CREATE :
cHeader = ' ';
return 0;
case WM_PAINT :
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC, 100, 100, &cHeader, 1);
TextOut(hDC, 100, 150, szData, strlen(szData));
EndPaint(hWnd, &ps);
return 0;
case WM_COMMAND :
switch(LOWORD(wParam))
{
case 100 :
SaveProc();
break;
case 200 :
LoadProc();
cHeader = GetHeader();
strcpy(szData, GetData());
InvalidateRect(hWnd, NULL, FALSE);
break;
}
return 0;
case WM_DESTROY :
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void SaveProc(void)
{
HFILE hFile;
MYFILE tmpMyFile;
tmpMyFile.cHeader = 'A';
strcpy(tmpMyFile.szData, "This is File Data");
_lcreat("e:\\test.txt", 0);
hFile = _lopen("e:\\test.txt", OF_WRITE);
_lwrite(hFile, (char *)&tmpMyFile, sizeof(MYFILE));
_lclose(hFile);
}
void LoadProc(void)
{
HFILE hFile;
hFile = _lopen("e:\\test.txt", OF_READ);
_lread(hFile, (MYFILE *)&MyFile, sizeof(MYFILE));
_lclose(hFile);
}
char GetHeader(void)
{
return MyFile.cHeader;
}
LPSTR GetData(void)
{
return MyFile.szData;
}

위 프로그램은 하나의 구조체를 만든후에 그 구조체 맴버 변수에 값을 채운후에
그 구조체의 크기만큼 통채로 파일에 기록한후에 다시 그 구조체의 크기만큼 정보
를 읽어오는 기능을 가지고 있습니다. 그러면 소스를 보도록 합시다. 소스를 보면
제가 만든함수 네개가 눈에 띄는데 각각 어떤 역할을 하는지 봅시다.
void SaveProc(void)
{

이 함수는 구조체 멤버에 값을 채워넣은뒤에 그 정조를 파일에 저장하는 역할을 합
니다.
HFILE hFile;
파일을 열고 쓰기 위해서 위 변수를 선언했습니다.

MYFILE tmpMyFile;
tmpMyFile.cHeader = 'A';
strcpy(tmpMyFile.szData, "This is File Data");

구조체 변수에 값을 채워넣고 있는 구문입니다.
_lcreat("e:\\test.txt", 0);
파일에 쓰기 위헤서 먼저 파일을 생성하고 있습니다.
hFile = _lopen("e:\\test.txt", OF_WRITE);
파일을 열고 있습니다.
_lwrite(hFile, (char *)&tmpMyFile, sizeof(MYFILE));
_lclose(hFile);
파일에 정보를 기록한후에 파일을 닫는 구문입니다.
}
void LoadProc(void)
{
이 함수는 파일에서 정보를 가져오는 역할을 합니다.
HFILE hFile;
hFile = _lopen("e:\\test.txt", OF_READ);
_lread(hFile, (MYFILE *)&MyFile, sizeof(MYFILE));
_lclose(hFile);
역시 파일을 연후에 정보를 가져오고 닫는 과정을 보여 주고 있습니다.
}
char GetHeader(void)
{
return MyFile.cHeader;
}
LPSTR GetData(void)
{
return MyFile.szData;
}
위 두함수는 가져온 정보를 분리해서 그 값을 리턴해주는 역할을 합니다.
또 다른 방법으로 파일 입출력을 해보도록 하겠습니다. 이 방법은 앞에서
알아 본 방법보다는 약간 복잡하지만 꼭 알아 두셔야 합니다. 왜냐하면 이 방법
으로 통신 포트를 제어할수 있거든요. 원리는 앞부분하고 크게 다른점은 없습니다.
자 그러면 어떤 식으로 하는지 구체적으로 알아 봅시다. 먼저 약간 다른점이 하나
있습니다. 위에서 한 방법대로라면은 파일에 정보를 기록할때 먼저 파일을 생성하
고 그 다음에 그 파일을 열었는데 이번 방법으로는 그 과정을 하나의 함수로 할수
있습니다. 물론 그 함수의 파라미터에 파일을 생성하고 연다는 것을 지정하는 부분
이 있습니다. 아래 함수를 이용해서 파일을 열고 생성하는 과정을 할수 있습니다.
HANDLE CreateFile(
LPCTSTR lpszName,
DWORD fdwAccess,
DWORD fdwShareMode,
LPSECURITY_ATTRIBUTES lpsa,
DWORD fdwCreate,
DWORD fdwAttrsAndFlags,
HANDLE hTemplateFile
);
우리가 앞에서 알아본 파일 입출력함수들은 HFILE이라는 자료형을 사용했던것에 비
해서 지금부터 알아 볼 파일 핸들은 HANDLE이라는 자료형을 사용한다는 것을 알수
있습니다. 함수 리턴값을 보면 알겠죠? 자 그러면 각 파라미터에 어떤 값들을 지정
하는지 알아 봅시다. 조금 복잡하죠?
첫번째 파라미터인 lpszName에는 생성하거나 열 파일이름을 지정하면 됩니다. 두번
째 파라미터인 fdwAccess는 파일을 어떤식으로 열것인지를 지정하면 됩니다. 우리
가 앞에서 알아본 읽기 전용, 쓰기 전용 뭐 이런것들을 의미하는 거죠. 이 파라미
터에는 다음과 같은 예약어가 지정될수 있습니다.
GENERIC_READ 읽기 전용으로 파일을 엽니다.
GENERIC_WRITE 쓰기 전용으로 파일을 엽니다.
세번째 파라미터인 fdwShareMode는 파일을 공유할것인지 지정하는 곳인데 이곳에
지정될수 있는 예약어는 다음과 같습니다.
0 파일을 공유하지 않습니다.
FILE_SHARE_READ 다른 파일에서 읽는 것을 허락합니다.
FILE_SHARE_WRITE 다른 파일에서 쓰기를 허락합니다.
네번째 파라미터인 lpsa에는 보통 NULL값을 지정합니다. 그리고 다섯번째 파라미터
인 fdwCreate에는 파일에 대한 어떤 행동방식을 지정해 주는 것인데 이곳에 지정
될수 있는 예약어는 다음과 같습니다.
CREATE_NEW 파일을 생성합니다.
CREATE_ALWAYS 파일을 생성합니다.
OPEN_EXISTING 존재하는 파일을 엽니다.
OPEN_ALWAYS 파일을 엽니다.
파일을 생성하는 CREATE_NEW와 CREATE_ALWAYS의 차이점은 무엇일까요? CREATE_NEW
를 이용해서 파일을 생성할때 만약에 같은 이름의 파일이 존재하면 새로 생성하지
않습니다. 그러나 CREATE_ALWAYS는 덮어쓴다는 차이점이 있죠.
여섯번째 파라미터인 fdwAttrsAndFlags는 파일의 속성을 지정하는 것인데 이곳에는
다음과 같은 예약어가 올수 있습니다.
FILE_ATTRIBUTE_NORMAL 일반적인 파일을 의미합니다.
FILE_ATTRIBUTE_HIDDEN 히든 파일을 의미합니다.
FILE_ATTRIBUTE_READONLY 읽기 전용 파일을 의미합니다.
FILE_ATTRIBUTE_SYSTEM 시스템 파일을 의미합니다.
마지막 파라미터인 hTemplateFile에는 보통 NULL을 지정하여 사용합니다.
자 파일을 생성하고 여는 기능을 가진 함수인 CreateFile()함수에 대해 알아 보았
으니 다 사용한후에 닫는 함수를 알아 봅시다.
BOOL CloseHandle(
HANDLE hObject
);
파라미터로 파일을 열었을때 얻은 파일의 핸들을 지정해 주면 됩니다.
자 이번에는 파일에서 정보를 읽고 쓰는 함수에 대해 알아 보죠. 파일에 정보를 기
록할때에는 다음의 함수를 사용합니다.
BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
함수 이름에서도 쉽게 정보를 기록하는 역할을 한다는 것을 알수 있죠? 각 파라미터
가 의미하는 바를 알아 봅시다.
첫번째 파라미터에는 파일의 핸들을 지정해 주면 됩니다. 앞에서 알아본
CreateFile() 함수의 리턴값을 지정해 주면 됩니다. 두번째 파라미터인 lpBuffer는
정보를 저장하고 있는 버퍼의 주소를 의미합니다. 세번째 파라미터인
nNumberOfBytesToWrite는 버퍼의 크기를 의미하고 네번째 파라미터인
lpNumberOfBytesWritten은 실제로 기록된 정보의 크기값이 저장되는 변수의 주소입
니다. 마지막 파라미터인 lpOverlapped에는 보통 NULL을 지정하면 됩니다.
이번에는 정보를 읽어올수 있는 ReadFile() 함수에 대해 알아 보죠. 파라미터의
의미는 위 WriteFile() 함수와 같습니다.
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
자 그러면 우리가 앞에서 만들어 본 파일 입출력 예제 프로그램을 지금 배운 IO
함수를 이용해서 똑같이 구현해 보도록 합시다.

MyMenu MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Save", 100
MENUITEM "&Load", 200
END
END
#include <windows.h>
#include <string.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void SaveProc(void);
void LoadProc(void);
char GetHeader(void);
LPSTR GetData(void);
typedef struct tagMYFILE
{
char cHeader;
char szData[80];
} MYFILE;
MYFILE MyFile;
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
static char szAppName[] = "File & Directory Example";
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW|CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = "MyMenu";
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass))
return FALSE;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
static char cHeader;
static char szData[80];
switch(message)
{
case WM_CREATE :
cHeader = ' ';
return 0;
case WM_PAINT :
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC, 100, 100, &cHeader, 1);
TextOut(hDC, 100, 150, szData, strlen(szData));
EndPaint(hWnd, &ps);
return 0;
case WM_COMMAND :
switch(LOWORD(wParam))
{
case 100 :
SaveProc();
break;
case 200 :
LoadProc();
cHeader = GetHeader();
strcpy(szData, GetData());
InvalidateRect(hWnd, NULL, FALSE);
break;
}
return 0;
case WM_DESTROY :
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void SaveProc(void)
{
HANDLE hFile;
MYFILE tmpMyFile;
DWORD dwBuffer;
tmpMyFile.cHeader = 'A';
strcpy(tmpMyFile.szData, "This is File Data");
hFile = CreateFile("e:\\test.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hFile, (char *)&tmpMyFile, sizeof(MYFILE), &dwBuffer, NULL);
CloseHandle(hFile);
}
void LoadProc(void)
{
HANDLE hFile;
DWORD dwBuffer;
hFile = CreateFile("e:\\test.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(hFile, (MYFILE *)&MyFile, sizeof(MYFILE), &dwBuffer, NULL);
CloseHandle(hFile);
}
char GetHeader(void)
{
return MyFile.cHeader;
}
LPSTR GetData(void)
{
return MyFile.szData;
}

역시 마찬가지로 크게 네개의 함수가 보이죠? 각 함수를 보도록 합시다.
void SaveProc(void)
{
이 함수는 정보를 저장하는 역할을 합니다.
HANDLE hFile;
앞에서 알아 본 HFILE이라는 자료형 대신에 HANDLE이라는 자료형을 사용합니다.
MYFILE tmpMyFile;
DWORD dwBuffer;
tmpMyFile.cHeader = 'A';
strcpy(tmpMyFile.szData, "This is File Data");
hFile = CreateFile("e:\\test.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
파일을 생성해서 그 파일을 쓰기 전용으로 열고 있는 구문입니다. 일반적인 파일의
속성을 가진 파일이 생성되고 열리겠군요.
WriteFile(hFile, (char *)&tmpMyFile, sizeof(MYFILE), &dwBuffer, NULL);
CloseHandle(hFile);
파일에 정보를 기록하고 닫는 구문입니다.
}
void LoadProc(void)
{
이 함수는 파일에서 정보를 읽어오는 역할을 합니다.
HANDLE hFile;
DWORD dwBuffer;
hFile = CreateFile("e:\\test.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
존재하는 파일을 읽기전용으로 열고 있는 구문입니다.
ReadFile(hFile, (MYFILE *)&MyFile, sizeof(MYFILE), &dwBuffer, NULL);
CloseHandle(hFile);
파일에서 정보를 읽고 닫는 구문입니다.
}
char GetHeader(void)
{
return MyFile.cHeader;
}
LPSTR GetData(void)
{
return MyFile.szData;
}
읽어온 정보의 값을 되돌려 주고 있는 역할을 하는 것이 바로 위 두개의 함수입니
다.
 
반응형

'API 관련 > API 강좌모음' 카테고리의 다른 글

[강좌 20] 메모리  (0) 2007.10.26
[강좌 19] 초기화 파일  (0) 2007.10.26
[강좌 17] 폰트  (0) 2007.10.26
[강좌 16] 멀티미디어4  (0) 2007.10.26
[강좌 15] 멀티미디어3  (0) 2007.10.26
Comments