0103) 퍼옴 / CreateFile, WriteFile, ReadFile 퍼옴2011. 1. 3. 16:16
[ 파일 입출력 ]
파일을 열고 출력하는 간단한 예제
test.txt 라는 파일을 만들고 그 내용을 "I am Hacker" 이라고 한다음 이 파일을
컴파일하려는 실행파일과 같은 폴더에 넣고 컴파일후 실행파일을 실행해보면
파일 입출력 예를 확인 할수 있다.
-------------------- CreateFile 예 --------------------
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First"); //윈도우 이름 및 타이틀바에 등록할 문자열
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
//------------ 아래 부분은 윈도우 클래스를 설정해주는 것이다. --------------------
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
//------------ 위 부분은 윈도우 클래스를 설정해주는 것이다. --------------------
RegisterClass(&WndClass); // <-- 여기서는 위에서 설정한 클래스를 등록한다.
hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL); // 설정하고 등록한 윈도우를 생성한다.
ShowWindow(hWnd,nCmdShow); //생성한 윈도우를 출력..(이 함수를 호출하지않으면 윈도우가 보이지 않는다.)
while(GetMessage(&Message,NULL,0,0)) //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
HANDLE hFile = NULL;
char buf[1024] = {0};
DWORD dwByte = 0;
switch(iMessage)
{
case WM_LBUTTONDOWN:
hFile = CreateFile(TEXT("test.txt"),GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if(hFile == INVALID_HANDLE_VALUE) MessageBoxA(0,"CreateFile Error","OK",0);
if( ReadFile(hFile,buf,1024,&dwByte,NULL) == FALSE ) MessageBoxA(0,"ReadFile Error","OK",0);
MessageBoxA(0,buf,"Read",MB_OK);
CloseHandle(hFile);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,iMessage,wParam,lParam); //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}
-------------------------------------------------------
※ 파일핸들에 파일을 연결하면 그 순간부터 메모리에는 입출력 버퍼라는 공간이
생기고 이것을 이용해서 하드디스크에 저장한다고 한다. 그래서 만약 파일을 다 사용하고나서
파일핸들을 닫지 않는다면 입출력 버퍼가 계속 남아 있기 때문에 시스템의 자원이 낭비가 된다.
물론 프로그램이 끝날때는 자동으로 반환되지만 아직 끝나지 않고 실행을 더해야 한다면
문제를 일으킬수도 있다.
---------------------------------------------------------------------------
=================================================================================
[ CreateFile ]
------------------함수 원형------------------
HANDLE CreateFile (
LPCTSTR lpFileName,
DWORD deDesiredAccess,
DWORD deShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
---------------------------------------------
많은 인자를 갑고 있다. 파일 뿐만 아니라..
파이프, 메일 슬롯, 콘솔, 직렬, 병렬 포트 등의 오브젝트를 만들거나 열기도 하는 아주
복잡한 함수다. 간단하게 인수를 확인해보자
---------------------------------------------------
인자설명 :
===== lpFileaName =====
열거나 만들고자 하는 파일의 완전경로를 문자열로 지정한다. 완전경로 이므로 드라이브, 디렉토리,
파일명, 확장자가 한꺼번에 들어갈 수 있으며 네트워크 경로까지 지정할 수도 있다.
문자열의 길이는 MAX_PATH 이하여야 한다. MAX_PATH의 길이는 운영체제 버전에 따라
달라지겠지만 일단은 260이라고 생각하면 된다. 완전 경로뿐만 아니라 UNC까지 지원하므로
"\\서버\공유명\디렉토리\파일" 형식으로 공유된 파일을 열 수 있고
\\122.233.69.180\뭐뭐 식으로 IP를 직접 지정하면 지구상의 어떤 파일도 열 수 있다.
물론 이렇게 되려면 해당 서버에 접근할 수 있는 권한이 있어야 한다.
===== dwDesiredAccess =====
파일의 액세스 타입, 즉 파일로부터 데이터를 읽을 것인지 쓸것인지를 지정한다. 파일로부터 데이터를
읽기만 하면 GENERIC_READ 플래그를 주고 쓰기만 하면 GENERIC_WRITE 플래그를 주되
읽기도 하고 쓰기도 할 것이면 두 플래그를 OR 연산자로 연결하면 된다.
이외에 Win32의 다양한 엑스스 권한 플래그를 줄 수 있으나 파일 입출력을 할 때는
위에 보이는 두 플래그만 사용해도 충분한다.
===== dwShareMode =====
열려진 파일의 공유모드를 지정한다. 이 인수가 0 이면 파일은 공유되지 않으며 이미 열려진
파일을 또 열 수 없게 된다. 공유하고자 할 경우 다음 세 가지 중 하나를 지정한다.
다음 장에서 각 플래그에 따라 어떤 효과가 있는지 예제를 만들어 볼 것이다.
----------------------------------------------
플래그 설명
----------------------------------------------
FILE_SHARE_DELETE NT에서만 쓸수있으며 삭제 엑세스에 대해서만 파일을 열수 있다.
FILE_SHARE_READ 읽기 모드로 열 때만 파일을 열 수 있다.
FILE_SHARE_WRITE 쓰기 모드로 열 때만 파일을 열 수 있다.
===== lpSecurityAttributes =====
리턴된 핸들을 차일드 프로세스로 상속할 것인지 아닌지를 지정하는
SECURITY_ATTRIBUTES 구조체의 포인터이다. 사용하지 않을 경우 NULL을 지정한다.
===== dwCreationDisposition =====
만들고자 하는 파일이 이미 있을 경우, 또는 열고자 하는 파일이 없을 경우의 처리를 지정한다.
즉 일종의 비정상적인 상황에 대한 처리 지침이라고 할 수 있는데 다음 플래그 중 하나를 지정한다.
----------------------------------------------
플래그 설명
----------------------------------------------
CREATE_NEW 새로운 파일을 만들되 만약 지정한 파일이 이미 있으면 만들지 않는다.
CREATE_ALWAYS 새로운 파일을 만들되 만약 지정한 파일이 이미 있으면 기존의 파일을 삭제하고
다시 만든다. 이때 파일의 속성은 다시 설정된다.
OPEN_EXISTING 이미 있는 파일을 열되 만약 파일이 없으면 에러 코드를 되돌린다.
OPEN_ALWAYS 파일을 열되 만약 없으면 새로 만든다.
TRUNCATE_EXISTING 파일을 열고 파일의 크기를 0으로 만든다. 이 플래그를 쓰려면
GENERIC_WRITE 모드로 파일을 열어야 한다.
--------------------------------------------------------------
어떤 플래그를 사용할 것인가는 아주 신중하게 선택해야 한다. 이 플래그를 잘못 선택했다가는
멀쩡하던 파일이 새로 만들어질 수도 있고 있지도 않은 파일을 만든 후 있다고 우기는 이상한 사태가
발생할 수도 있다. 예를 드렁 사용자가 선택한 그래픽 파일을 보여주는 프로그램에서 그래픽 파일을
OPEN_ALWAYS 로 열었다고 해 보자. 그러면 CreateFile은 파일이 없으면 만든 후 핸들을 반환하므로
이 프로그램은 사용자가 선택한 파일이 진짜 그래픽 파일인줄 알게 될 것이며 당연히 그래픽은 제대로
출력될 리가 없다.
이때는 없으면 없다고 에러 코드를 번환하는 OPEN_EXISTING을 사용하는 것이 옯다. 생성할 때도
마찬가지로 이미 파일이 있을 경우 덮어쓰고 새로 만들 것인지, 에러를 반환할 것인지 잘 결정해야
한다. 에러를 리턴하지 않고 파일을 덮어써 버리면 기존의 존재하던 파일이 불시에 파괴되는 사고가
발생할 수도 있다. 플래그 뒤에 ALWAYS가 있는 것들은 무조건이라는 뜻이며 그렇지 않은 플래그는
비정상적인 상황일 때 에러를 리턴한다는 차이가 있다.
===== dwFlagsAndAttirbutes =====
이 인수는 파일의 속성과 여러 가지 옵션을 설정한다. 우선 파일의 속성에는 다음 플래그 중
원하는 것들을 OR 연산자로 묶어줄 수 있다.
----------------------------------------------
속성 설명
----------------------------------------------
FILE_ATTRIBUTE_ARCHIVE 아카이브 속성
FILE_ATTRIBUTE_HIDDEN 숨은 파일
FILE_ATTRIBUTE_NORMAL 아무 속성도 가지지 않은 보통파일. 이 플래그는 반드시
단독으로 사용되어야 한다.
FILE_ATTRIBUTE_OFFLINE 연결되지 않은 저장 장치에 있어 즉시 사용할 수 없는 파일
FILE_ATTRIBUTE_READONLY 읽기 전용
FILE_ATTRIBUTE_SYSTEM 운영체제가 배타적으로 사용하는 파일
FILE_ATTRIBUTE_TEMPORARY 임시 저장소에 저장되는 파일, 이 속성의 파일은 디스크에 저장
되지 않고 메모리에 저장되므로 입출력 속도가 빠르다. 사용후
반드시 지워야한다.
----------------------------------------------------------
파일 속성 플래그 외에 다음과 같은 옵션을 OR 연산자로 묶어서 같이 지정할 수 있다.
다음 플래그 외에 파이프와 함께 사용하는 몇 개의 옵션들도 있으나 이는 생략하였다.
굉장히 고급 플래그들이다.
----------------------------------------------
속성 설명
----------------------------------------------
FILE_FLAG_WRITE_THROUGH 데이터 출력시 캐시를 통해 곧바로 디스크로출력한다.
이 플래그를 지정하면 플러쉬가 더 빨라진다.
FILE_FLAG_OVERLAPPED 비동기 입출력을 행한다.
FILE_FLAG_NO_BUFFERING 버퍼나 캐시 없이 파일을 연다.
FILE_FLAG_RANDOM_ACCESS 임의 접근 파일임을 알린다.
FILE_FLAG_SEQUENTIAL_SCAN 순차 접근 파일임을 알린다. 이상의 두 플래그는 시스템이
캐시를 최적화하는데 도움을 줄 뿐이며 이 플래그를 지정했다고
해서 반드시 순차 입출력만 할 수 있는 것은 아니다.
FILE_FLAG_DELETE_ON_CLOSE 핸들이 닫힐 때 파일을 삭제한다.
FILE_FLAG_BACKUP_SEMANTICS 백업이나 리스토어를 위해 파일이 열리거나 만들어질 것을 지시한다.
FILE_FLAG_POSIX_SEMANTICS POSIX 규칙대로 파일을 액세스한다. 이 플래그로 만들어진 파일은
도스나 16비트 윈도우즈에서 읽을 수 없다.
FILE_FLAG_OPEN_REAPRSE_POINT NTFS의 reparse를 금지시킨다.
FILE_FLAG_OPEN_RECALL 원격 저장 장치에서 사용하는 플래그이다.
----------------------------------------------------------------------
===== hTemplateFile =====
새로 만들고자 하는 파일의 추가 속성을 지원하는 템플릿 파일의 핸들을 지정한다 윈95/98은
이 인수를 지원하지 않으며 큰 실용이 없으므로 이 인수는 통상 사용되지 않는다 NULL로 지정하는 것이
보통이다.
----------------------------------------------------------------------
===== 리턴 값 =====
파일을 열거나 만들기에 성공했다면 파일의 핸들을 리턴한다. 어떤 이유로 파일 열기에 실패하면
INVALID_HANDLE_VALUE 를(을) 리턴하는데 이 함수가 리턴하는 값은 반드시 점검해 보아야 한다.
멀티 태스킹 환경에서 파일이란 있다가도 금방 사라질 수 있는 존재이기 때문에 입출력 과정 전반에
걸쳐 에러 처리를 섬세하게 해야 한다. 주의할 것은 이 함수가 실패했을 때 리턴하는
INVALID_HANDLE_VALUE 값은 -1로 지정되어 있다는 점이며 0 이 아니라는 것을 항상 생각해야 한다.
그래서 흔 하던 습관대로 if(hFile == NULL) 이렇게 비교하는 것은 틀린 에러 처리다 상식과 틀리므로
꼭 기억하기 바란다.
========================================================================
[ 파일 쓰기 ]
파일에 데이터를 슬 때는 다음 함수를 사용한다.
------------------- 파일 쓰기 ------------------
BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
인자
- hFile : 대상 파일 핸들
- lpBuffer : 데이터가 들어갈 버퍼
- nNumberObBytesToWrite : 쓰고자하는 바이트 수
- lpNumberOfBytesWritten : 실제로 쓰여진 바이트 수가 저장되기때문에 DWORD형 포인터
- lpOverlapped : 비동기 입출력을 할때 사용한다 보통 NULL로 지정
----------------------------------------------------
파일 읽기도 위의 WriteFile 함수와 거의 동일하다. 그래서 아래에서
WriteFile 함수의 예제를 확인해보자
---------------------- WriteFile 함수 예 --------------------------
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First"); //윈도우 이름 및 타이틀바에 등록할 문자열
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
//------------ 아래 부분은 윈도우 클래스를 설정해주는 것이다. --------------------
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
//------------ 위 부분은 윈도우 클래스를 설정해주는 것이다. --------------------
RegisterClass(&WndClass); // <-- 여기서는 위에서 설정한 클래스를 등록한다.
hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL); // 설정하고 등록한 윈도우를 생성한다.
ShowWindow(hWnd,nCmdShow); //생성한 윈도우를 출력..(이 함수를 호출하지않으면 윈도우가 보이지 않는다.)
while(GetMessage(&Message,NULL,0,0)) //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
HANDLE hFile = NULL;
char buf[1024] = "I am Hacker!!\n";
DWORD dwByte = 0;
switch(iMessage)
{
case WM_LBUTTONDOWN:
hFile = CreateFile(TEXT("c:\\windows\\temp\\test.txt"),GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
if(hFile == INVALID_HANDLE_VALUE) MessageBoxA(0,"CreateFile Error","ok",0);
if( WriteFile(hFile,buf,sizeof(buf),&dwByte,NULL) == FALSE )
MessageBoxA(0,"WriteFile Error","ok",0);
CloseHandle(hFile);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,iMessage,wParam,lParam); //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}
[출처] [26장] 파일 입출력1 - CreateFile , WriteFile , |작성자 어른아이
'퍼옴' 카테고리의 다른 글
0715) Windows Azure (0) | 2011.07.15 |
---|---|
0712) 디자인 패턴 (0) | 2011.07.12 |
0101) 비주얼 스튜디오 단축키 (0) | 2011.01.01 |
퍼옴) C 프로그래머가 알아야 할 어셈블리. (0) | 2010.11.28 |
어셈블리 명령어 (0) | 2010.11.28 |