Programming/MFC

CDocument 클래스와 파일 처리

_Erato 2006. 3. 20. 19:33
출처 카페 > 윈도우 프로그래밍 플러스 | 김은철
원문 http://cafe.naver.com/pplus/169



CDocument 클래스는 파일에 관련된 처리를 하지 않는다면 그리 필요한 클래스는 아니다.

일반적으로 이 클래스에서는 새 파일, 열기, 저장, 다른 이름으로 저장을 처리하는데,

MFC로 SDI(Single Document Interface) 프로그램을 만들면 기본적으로 다음 그림과 같은

ID가 생성된다.



프로그램은 처음 실행될 때 항상새 파일(ID_FILE_NEW)메시지를 내부적으로 부르게 되어 있다.

새 파일은 InitInstance의ProcessShellCommand에 의해 내부적으로 호출된다.


BOOL CCabinetApp::InitInstance()
{

    ...

   // Dispatch commands specified on the command line
   if(!ProcessShellCommand(cmdInfo))       // 새로운 문서를 생성(ID_FILE_NEW)
       returnFALSE;

    ...

}


결과적으로ProcessShellCommand는 내부에서 CDocument의  OnNewDocument() 함수를

호출한다. 그래서 OnNewDocument() 함수는 프로그램 실행 시 반드시 한 번 불려진다.


BOOL CTestDoc::OnNewDocument()
{
   if(!CDocument::OnNewDocument())
        returnFALSE;

   // TODO: add reinitialization code here
   // (SDI documents will reuse this document)

   returnTRUE;
}


만약 프로그램 초기화 시 파일을 읽어서 화면에 표현해야 한다면, 다음과 같이 코딩해야 한다.


BOOL CCabinetApp::InitInstance()
{

    ...

   // Dispatch commands specified on the command line
    //if (!ProcessShellCommand(cmdInfo))        // 막아 놓고
    //    return FALSE;


   // 우선 새로운 빈 문서를 생성한다.

    CTestDoc* pDoc = (CTestDoc*)pDocTemplate->OpenDocumentFile( NULL );

    CString strPath = "c:\\project\\test.txt";
    // CTestDoc 클래스에서 파일을 열어서 처리할 수 있도록OnOpenDocument를 호출한다.

    pDoc->OnOpenDocument( strPath );
   
    ...

}


위의OnOpenDocument()함수는 CTestDoc의OnOpenDocument()함수를 호출한다.


BOOL CTestDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
   if(!CDocument::OnOpenDocument(lpszPathName))  // Serialize를 호출
       returnFALSE;

   

   returnTRUE;
}


호출된OnOpenDocument() 함수에서CDocument::OpOpenDocument() 함수를 호출하고,

결국CDocument::OpOpenDocument() 함수는 내부적으로Serialize() 함수를 호출해 준다.

그러면 아래의Serialize() 함수가 호출되는데, 이 곳에 파일과 관련된 처리를 하면 된다.

이미 파일은 개방이 되어 있는 상태이고, 파일을 읽을 수 있는 CArchive 객체가 매개 변수로

넘어오게 된다. 그러므로 이CArchive객체를 사용하여 아래와 같이 파일을 읽을 수 있다.


void CCabinetDoc::Serialize(CArchive& ar)
{
   if(ar.IsStoring())     // 저장을 하기 위한 객체이면
    {
         int count = 5;

         ar << count;     // 파일에 count를 저장, OnSaveDocument() 함수 호출 시 사용
    }
   else
    {
        int count;

       ar >> count;   // 파일에서 count를 읽음
    }
}


Serialize() 함수는 CDocument::OnSaveDocument() 함수의 호출에 의해서도 호출된다.


BOOL CCabinetDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
   returnCDocument::OnSaveDocument(lpszPathName);     // Serialize() 함수를 내부적으로 호출
}


위에서 파일 읽는 것을 Serialize()를 사용하지 않고 처리하려면, 다음과 같이 함수 호출 부분을

주석으로 처리한 후, CFile 클래스 등을 이용하여 처리할 수 있다.


BOOL CTestDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
    //if (!CDocument::OnOpenDocument(lpszPathName))   // Serialize를 호출
    //    return FALSE;

   

    CFile file;

    file.Open( lpszPathName, CFile::modeRead );

    ...// 파일 읽기

    file.Close();


   returnTRUE;
}


또한 파일 쓰는 것을 Serialize()를 사용하지 않고 처리하려면, 다음과 같이 함수 호출 부분을

주석으로 처리한 후, CFile 클래스 등을 이용하여 처리할 수 있다.


BOOL CCabinetDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
    //return CDocument::OnSaveDocument(lpszPathName);      // Serialize() 함수를 내부적으로 호출

 

    CFile file;

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

    ... // 파일 쓰기

    file.Close();


   returnTRUE;
}


참고로,ID_FILE_NEWID_FILE_OPEN은 CTestApp 클래스에 다음과 같이 매크로가 존재한다.


BEGIN_MESSAGE_MAP(CTestApp, CWinApp)
 //{{AFX_MSG_MAP(CTestApp)
 ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
  // NOTE - the ClassWizard will add and remove mapping macros here.
  //    DO NOT EDIT what you see in these blocks of generated code!
 //}}AFX_MSG_MAP
 // Standard file based document commands
 ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
 ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
 // Standard print setup command
 ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()


만약에 ID_FILE_NEW와 ID_FILE_OPEN을 직접 처리하고자 한다면, 위 두 줄을 주석처리해야 한다.

종합적으로 파일 처리에 대해 정리를 해 보면,


ID_FILE_NEW는 처음 프로그램이 실행될 때 발생되며, 이 때 CDocument 클래스의 OnNewDocument()

함수가 호출된다. 이 이벤트는 SDI로 프로그램을 생성하였을 때 CWinApp의 OnFileNew() 함수와 연결이

되어 있으며, 사용자가파일 >> 새 파일을 누를 때도 발생한다. OnFileNew() 함수의 역할은 새로운

도큐먼트를 생성하고, 생성된 도큐먼트의 OnNewDocument() 함수를 호출해 주는 것이다. 만약 도큐먼트를

초기화 해주어야 한다면, OnNewDocument() 함수가 적합하다.


ID_FILE_OPEN메시지는 CWinApp 클래스의OnFileOpen() 함수를 호출한다. 사용자가파일 >> 열기

메뉴를 선택하면, 이 메시지가 발생되며, 파일을 선택할 수 있는 대화 상자를 보여 준다. 대화 상자에서

사용자가 파일을 선택한 후 열기 버튼을 누르면, 도큐먼트의 OnOpenDocument() 함수가 자동적으로

호출된다. 그러면OnOpenDocument() 함수는 연속적으로Serialize() 함수를 호출해 준다. 우리는

Serialize() 함수에서 CArchive 객체를 사용해서 파일을 읽을 수 있다.


ID_FILE_SAVE메시지는 CDocument 클래스의OnFileSave() 함수를 호출한다. 이 함수는 다시 CTestDoc

클래스의 OnSaveDocument() 함수를 호출한다. 그러면OnSaveDocument() 함수는 연속적으로 Serialize()

함수를 호출해서 CArchive 객체를 사용한 파일 저장을 가능하게 한다.


ID_FILE_SAVE_AS메시지는 CDocument 클래스의OnFileSaveAs() 함수를 호출한다. 나머지 기능은

OnFileSave() 함수와 같다.


CArchive 클래스는 CFile 클래스의 객체를 사용하여, 파일 입출력을 가능하게 해주는 클래스이다.


Serialize를 사용한 데이터의 저장


int  a = 5, b = 10;

ar<< a << b;


Serialize를 사용한 데이터의 읽기


int a, b;

ar>> a >> b;    // a는 5, b는 10이 읽힘