본문 바로가기

카테고리 없음

mfc CFile

9. 파일 처리

 

(1) C언어

 

I/O함수는 스트림(Stream)으로 처리된다.

스트림은 일련의 데이터들로 ( Sequence of Data ), 실제 디바이스(물리적으로 연결되는 곳)로 연결된다. 예를 들어 C의 표준 스트림으로 stdout스트림은 스크린으로, stdin스트림은 키보드로 연결된다. I/O함수 중 fprintf()는 어떤 스트림과도 작동하게 되어 있으며, printf()는 그 중에서 stdout과 작동하도록 고정되어 있는 함수이다.

 

) printf(Hello) fprintf(stdout, Hello)와 같다.

 

디스크 파일도 하나의 디바이스이므로, 파일 스트림과 연결시키면 된다. ( fopen()의 역할 )

파일이 오픈 되었다는 것은 이들 I/O버퍼의 공간이 발견되어, 그 버퍼의 포인터가 반환된다는 의미이다. FILE포인터를 스트림이라 부른다.

( stdin이나 stdout은 이미 오픈 되어있는 Device용 버퍼이다. )

 

 

)         프로젝트명 : C_fopen

// 파일 쓰기

#include <stdio.h>

main()    {

             FILE *pFile;          // typedef 되어있는 구조체. 버퍼 위치 등의 정보로 구성.

             if((pFile = fopen("hello.txt", "w")) != NULL)      {            // pFile과 실제 hello.txt 파일 연동

                           fprintf(pFile, "Hello, World.");                         // pFile이 스트림

                           fclose(pFile);                                                // 문법적으로는 FILE포인터이다.

             }

             else printf("Error writing hello.txt\n");

             return 0;

}

 

// 결과 확인 : 메모장으로 파일 읽기


(2) CFile클래스의 기본적 사용법.

 

예제)      프로젝트명 : FileBasic

Dialog Based

 

void CFileBasicDlg::OnBtOpen()

{

             char szFilter[] = "실습용 파일(*.fle)|*.fle|모든파일(*.*)|*.*||";

             CFileDialog dlg(TRUE,"fle", "test", OFN_FILEMUSTEXIST,szFilter);

 

             if(dlg.DoModal() == IDOK){           

                           CFile file;

                           char aTemp[100]="";                                                            

                           file.Open(dlg.GetFileName(), CFile::modeRead);

                           file.Read(aTemp, file.GetLength());

                           file.Close();                     

                           m_strEdit = aTemp;

                           UpdateData(FALSE);

             }

}

void CFileBasicDlg::OnBtStore()

{

             char szFilter[] = "실습용 파일(*.fle)|*.fle|모든파일(*.*)|*.*||";

             CFileDialog dlg(FALSE,"fle", "test", OFN_CREATEPROMPT| OFN_OVERWRITEPROMPT,szFilter);

             if(dlg.DoModal() == IDOK){

                           CFile file;

                           char aTemp[100];

                           UpdateData(TRUE);

                           sprintf(aTemp, LPCTSTR(m_strEdit));        

 

                           file.Open(dlg.GetFileName(), CFile::modeCreate|CFile::modeWrite);

                           file.Write(aTemp, m_strEdit.GetLength());

                           file.Close();        

             }

}


(3) CFile CArchive 연동

 

예제)      프로젝트명 : FileArchive연동

 

void CFileBasicDlg::OnBtOpen()

{

             char szFilter[] = "실습용 파일(*.fle)|*.fle|모든파일(*.*)|*.*||";

             CFileDialog dlg(TRUE,"fle", "test", OFN_FILEMUSTEXIST, szFilter);

             if(dlg.DoModal() == IDOK){           

                           CFile file(dlg.GetFileName(), CFile::modeRead);

                           CArchive ar(&file, CArchive::load);

                           Serialize(ar);

 

                           UpdateData(FALSE);

             }

}

 

void CFileBasicDlg::OnBtStore()

{

             char szFilter[] = "실습용 파일(*.fle)|*.fle|모든파일(*.*)|*.*||";

             CFileDialog dlg(FALSE,"fle", "test", OFN_CREATEPROMPT| OFN_OVERWRITEPROMPT, szFilter);

             if(dlg.DoModal() == IDOK){

                           UpdateData(TRUE);

 

                           CFile file(dlg.GetFileName(), CFile::modeCreate|CFile::modeWrite);

                           CArchive ar(&file, CArchive::store);

                     Serialize(ar);

             }

}

 

Serialize함수를 OverRide한다.

 

void CFileBasicDlg::Serialize(CArchive& ar)

{

             if (ar.IsStoring())

             {            // storing code

                           ar<<m_strEdit;

             }

             else

             {            // loading code

                           ar>>m_strEdit;

             }

}


윈도우즈에서 파일 입출력에 대한 처리방법은 여러가지가 있는데, 가장 쉬
운방법은 MFC 클래스 라이브러리에서 기본적으로 제공되고 있는 표준 다이
얼로그 박스(Common Dialog Box)클래스를 이용하는 것입니다. 표준 다이얼
로그 박스는 문자열의 검색과 치환, 색상의 선택, 폰트의 선택, 프린팅에
대한 기능들도 표준 다이얼로그 박스 클래스로 제공되고 있기 때문에 이러
한 기능들을 프로그램에 지원하고자 할 때는 표준 다이얼로그 박스를 이용
하는 것이 훨씬 용이합니다.

Visual C++은 윈도우즈 상에서 보다 효율적으로 파일처리를 할 수 있도록
CFile 클래스와 직렬화(Serialization)기능을 제공하고 있습니다.

CFile 클래스

MFC는 표준 파일 처리를 위해 CFile 클래스를 제공하고 있습니다. 이 CFile 
클래스에는 파일처리를 위한 많은 멤버함수들이 포함되어 있는데, 이러한
함수들은 이전에 도스상에서 자주 다루어 보았던 함수들과 유사합니다.

 

멤버함수

의미

CFile()
Abort()
Duplicate()
Open()
Close() 
 
Read()
Write()
Flush() 
 
Seek()
SeekToBegin()
SeekToEnd()
GetLength()
SetLength()
 
LockRange()
UnlockRange()
 
GetPosition()
GetStatus()
GetFileName()
GetFileTitle()
GetFilePath()
SetFilePath()
 
Rename()
Remove()
GetStatus()
SetStatus() 
객체 생성자.
모든 경고와 에러들을 무시하고 화일을 닫는다.
오브젝트 복사.
파일을 연다.
파일 종료 및 오브젝트 삭제.
 
파일로 부터 데이타를 읽는다.
현재파일 위치에 데이타를 쓴다.
데이타를 제거한다.   
  
파일포인터를 이동한다.
파일 포인터를 처음으로 이동한다.
파일 포인터를 끝으로 이동한다.
파일의 길이를 얻는다.
파일의 길이를 지정한다.
   
파일의 일부를 락(Lock)을 건다.
파일의 일부를 락에서 해제한다. 
 
파일의 포인터를 얻는다.
지정된 파일의 상태를 얻는다.
선택된 파일의 파일이름을 얻는다.
선택된 파일의 타이틀을 얻는다.
선택된 파일의 전체 경로를 얻는다.
선택된 파일의 전체 경로를 설정한다.  
 
지정된 파일을 다른이름으로 변경한다.
지정된 파일을 제거한다.
지정된 파일의 상태를 얻는다.
지정된 파일의 상태를 설정한다.      

 

멤버함수들을 알았으니 CFile 클래스로 파일 쓰기와 파일 읽기 예제를 보
면서 공부해 보겠습니다.

#파일쓰기 예제

void CFileioView::OnWritefile()
{
   CFile Wfile;
   if(!Wfile.Open("TestFile.txt", CFile::modeCreate :
                    CFile::modeWrite))
   {
       MessageBox("Can't Create testfile.txt !", "Warning",
                       MB_OK : MB_ICONHAND);
       return;
   }
   char* ps = new char[27];
   char* ps2 = ps;

   for(int i=0;i<26;i++)
       *ps2++ = 'A'+i;
   *ps2 = NULL;    // NULL 문자로 끝나게 한다.
   Wfile.Write(ps,27);
   Wfile.Close();
   delete ps;
}

#파일읽기 예제

void CFileioView::OnReadfile()
{
   CFile Rfile;
   if(!Wfile.Open("TestFile.txt", CFile::modeRead))
   {
       MessageBox("Can't Open testfile.txt !", "Warning",
                       MB_OK : MB_ICONHAND);
       return;
   }
   UINT FileLength = (UINT)Rfile.GetLength();

   char* ps = new char[FileLength];
   Rfile.Read(ps,FileLength);
   Rfile.Close();

   CClientDC dc(this);
   dc.TextOut(0,0,ps,lstrlen(ps));
   delete ps;
}

마지막으로 파일의 특정위치에 데이타를 읽거나 쓸수 있도록 처리해주는 
CFile 클래스의 Seek()멤버함수를 이용해보겠습니다.

#랜덤 파일 처리 예제

void CFileioView::OnAddfile()
{
   CFile Afile;
   if(!Afile.Open("TestFile.txt", CFile::modeRead :
                    CFile::modeWrite))
   {

       MessageBox("Can't Create testfile.txt !", "Warning",
                       MB_OK : MB_ICONHAND);
       return;
   }
   Afile.Seek(-1,CFile::end);
   ~~~~~~~~~~~~~
   char* ps = new char[27];
   char* ps2 = ps;
   for(int i=0;i<26;i++)
       *ps2++ = 'a'+i;
   *ps2 = NULL;    // NULL 문자로 끝나게 한다.
   Wfile.Write(ps,27);
   Wfile.Close();
   delete ps;
}

참고로 Seek()함수에 대해서 알아보겠습니다...

Seek()함수의 첫번째 매개 변수는 양수이면 앞쪽으로 파일포인터를 이동하
고, 음수이면 뒷쪽으로 파일포인터를 이동합니다. 두번째 매개 변수는 파일
의 첫번째 위치를 기준으로 파일포인터를 이동하고자 하면 CFile:begin 플
래그를 사용하고, 현재위치나 파일의 마지막을 기준으로 이동하고자 한다면
CFile::end 플래그를 사용하면 됩니다.
CFile 클래스는 이 함수 외에도 SeekToBegin()와 SeekToEnd()함수를 제공
하고 있습니다.

 

이번엔 파일의 예외처리에 대해서 알아보겠습니다...

⊙ 예외처리(Exception Handling)

MFC는 파일예외처리를 위해서 CFileException 클래스를 제공하고 있습니다
CFileException 클래스는 파일을 오픈하면서 발생되는 여러가지 에러에 관
련된 정보를 포함하고 있습니다.
파일처리에 있어서 발생되는 에러는 CFileException 클래스의 m_cause 데
이타 멤버의 값을 참조하게 됩니다. 파일 에러가 발생했을때 m_cause데이타
멤버에 발생된 에러코드가 들어가게 되는데, 이것들에는 다음과 같은 것들
이 있습니다.

   에러코드

none
generic
fileNotFound
badPath
tooManyOpenFiles
accessDenied
invalidFile
removeCurrentDir
directoryFull
badSeek
hardIO
sharingViolation
lockViolation
diskFull
endOfFile
에러가 없다
일반적인 에러
파일이 존재하지 않는다
파일 경로가 맞지 않다
허용된 파일 오픈 수를 넘었다
파일 접근 금지
파일에 이상이 있다
현재 디렉토리를 제거할 수 없다
디렉토리가 모두 찼다
파일 포인터 지정에러
하드웨어 에러
SHARE.EXE가 로드되지 않았거나 공유된 지역에 락이 걸렸을 경우
이미 락이 걸려 있는 지역에 락을 시도했다
디스크가 모두 찼다
파일의 끝에 도달하였다

 

실행에러 즉, 예외처리를 하는 TRY, CATCH, END_CATCH 매크로가 사용됩니
다. 이들 매크로는 메모리(CMemoryException), 리소스(CResourceException)
, OLE(COleException)등에 관련된 예외처리를 담당합니다.

예>
    // example for CFileException::m_cause
    extern char* pFileName;
    TRY
    {
         CFile f(pFileName, CFile::modeCreate : CFile::modeWrite);
    }
    CATCH(CFileException, e)
    {
         if(e->m_cause == CFileException::fileNotFound)
                                          ??????
              printf("ERROR : File not found\n");
    }

이번엔 switch ~ case 문으로 해볼까요?

    extern char* pFileName;

    TRY
    {
         CFile f(pFileName, CFile::modeCreate : CFile::modeWrite);
    }

    CATCH(CFileException, e)
    {
         switch(e->m_cause)
         {
              case CFileException::fileNotFound :
                                   ??????
                   MessageBox("File not found");
                   break;
              case CFileException::diskFull :
                                   ????
                   MessageBox("Disk is full");
                   break;
                   :
                   :
         }

    }
    END_CATCH