달력

12

« 2024/12 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2011. 1. 3. 16:16

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);  //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}

'퍼옴' 카테고리의 다른 글

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
:
Posted by 투잌