Overview 파일입출력 CFile 클래스를이용한파일입출력기법 도큐먼트 / 뷰구조이해 CArchive 클래스를이용한직렬화기법 HCI Programming 2 (321190) 2007 년가을학기 11/5/2007 박경신 2 파일입출력방법 일반파일입출력 CFile ( 파생 ) 클래스 Read(), Write() 등의함수이용 직렬화 (serialization) 애플리케이션데이터가파일의형태로시스템드라이브에저장될때 CArchive 클래스 << 또는 >> 연산자이용 CArchive 와 CFile 클래스 CArchive 클래스는 CFile 객체에애플리케이션데이터를저장 Application Application Object Serialize Function CFile CArchive 3 4
CArchive 클래스 CDocument 클래스와 CFile 클래스를연결해주기위한클래스 IsStoring() : 읽기상태또는저장상태를판별 CDocument Serialize CArchive CMemFile CFile CSocketFile CArchive 중요멤버함수 IsLoading () CArchive 객체가자료를불러오는중인지를알수있음 IsStoring () CArchive 객체가자료를저장하는중인지를알수있음 연산자 >> CArchive 객체로부터객체나기본데이터형을읽음 연산자 << CArchive 객체에객체나기본데이터형을저장 Read() CArchive 객체로부터 byte 단위의블록을읽어옴 Write() CArchive 객체에바이트단위의블록을저장 메모리 디스크 네트워크 5 ReadString() CArchive 객체로부터문자열을읽어옴 WriteString() CArchive 객체에문자열을저장 6 MFC 클래스계층도 CFile 클래스핵심입출력연산 MFC 클래스계층도 파일입출력기능제공 파생클래스에공통의인터페이스제공 Open() 파일을열거나생성한다 Read() 파일포인터의위치에서데이터를읽는다 Write() 파일포인터의위치에데이터를쓴다 Seek() 파일포인터의위치를변경한다 Close() 파일을닫는다 7 8
CFile 클래스열기와생성 열기와생성 TRY CFile file("mytest.txt", CFile::modeReadWrite); // 방법 1 CATCH (CFileException, e) e->reporterror(); e->delete(); END_CATCH CFileException e; if(!file.open("mytest.txt", CFile::modeReadWrite, &e)) // 방법 2 9 CFile 클래스파일접근 / 공유모드 파일접근 / 공유모드 플래그 CFile::modeCreate CFile::modeNoTruncate 의미 파일을무조건생성한다. 같은이름의파일이있다면크기를 0 으로바꾼다. 연산자를이용하여 CFile::modeCreate 플래그와더불어사용하면같은이름의파일이있을경우크기를 0 으로바꾸지않고이파일을연다. CFile::modeRead 읽기전용모드로파일을열거나생성한다. CFile::modeReadWrite 읽기및쓰기모드로파일을열거나생성한다. CFile::modeWrite 쓰기전용모드로파일을열거나생성한다. CFile::shareDenyNone 다른프로세스에게파일에대한읽기 / 쓰기를허용한다. CFile::shareDenyRead 다른프로세스에게파일에대한읽기를금지한다. CFile::shareDenyWrite 다른프로세스에게파일에대한쓰기를금지한다. CFile::shareDenyExclusive 다른프로세스에게파일에대한읽기 / 쓰기를금지한다. 10 CFile 클래스닫기 닫기 : 방법 1 CFile 클래스닫기 닫기 : 방법 2 void CExFileView::OnLButtonDblClk(UINT nflags, CPoint point) CFileException e; if(!file.open("mytest.txt", CFile::modeReadWrite CFile::modeCreate, &e)) return; // 생략 // -> CFile::~CFile() 함수가호출된다. CFile 을사용하면객체가소멸시에자동으로파일을닫으므로 void CExFileView::OnLButtonDblClk(UINT nflags, CPoint point) CFileException e; if(!file.open("mytest.txt", CFile::modeReadWrite CFile::modeCreate CFile::modeNoTruncate, &e)) return; // 생략 file.close(); CFile을이용하여여러개의파일을다룰때 11 12 명시적으로파일을닫는함수를호출할필요가없다
CFile 클래스 Read, Write, Seek 읽기와쓰기 UINT CFile::Read (void* lpbuf, UINT ncount) ; void CFile::Write (const void* lpbuf, UINT ncount) ; 파일포인터위치변경 CFile 클래스데이터입출력 파일에데이터쓰기 int buffer[1000]; file.open(_( test.dat, CFile::modeCreate CFile::modeWrite); file.write(buffer, 1000 * sizeof(int)); file.close( ); ULONGLONG CFile::Seek (LONGLONG loff, UINT nfrom) ; nfrom 의미 CFile::begin 파일의처음위치부터 loff만큼파일포인터이동 CFile::current 현재의파일포인터위치부터 loff만큼파일포인터이동 CFile::end 파일의끝위치부터 loff만큼파일포인터이동 13 파일에서데이터읽기 file.open(_t( test.dat ), CFile::modeRead); int nlength = file.getlength( ); int *buffer = new BYTE [nlength]; file.read(buffer, nlength); file.close( ); 14 CFile 클래스에러처리 CFile 클래스기타함수 에러의가능성 지정한파일이디스크에존재하지않음 다른프로그램에서파일을사용 디스크가모두차서쓸공간부족 void main() TRY int buffer[1000]; file.open(_t( test.dat"), CFile::modeCreate CFile::modeWrite); file.write(buffer, 1000 * sizeof(int)); file.close( ); CATCH(CFileException, e) e->reporterror( ); END_CATCH 15 CFile::GetLength(), CFile::SetLength() 파일의현재크기를얻거나변경한다 CFile::GetPosition() 현재의파일포인터위치를얻는다 CFile::LockRange(), CFile::UnlockRange() 파일의일정영역을잠그거나해제한다. 잠근영역은다른프로세스가접근할수없다 CFile::GetFilePath(), CFile::GetFileName() 파일의전체경로 (Full Path) 와이름을얻는다 CFile::GetFileTitle() 확장자를제외한파일이름을얻는다 CFile::GetStatus(), CFile::SetStatus() 파일이생성된시간, 최종변경된시간, 크기, 속성등파일의 16 상태를얻는다. 파일의상태를지정한다
CMemFile 클래스 사용예 void CExFileView::OnLButtonDblClk(UINT nflags, CPoint point) CMemFile file; // 메모리파일에쓰기 int a = 100; file.write(&a, sizeof(a)); // 메모리파일에서읽기 file.seektobegin(); int b; file.read(&b, sizeof(b)); TRACE("b = %d\n", b); 17 CStdioFile 클래스 사용예 마우스를더블클릭하면 test2.txt 생성후복사 ReadString 과 WriteString 을제공, Text 파일을읽고쓰게함. void CExFileView::OnLButtonDblClk(UINT nflags, CPoint point) CStdioFile file1; // 읽기전용으로 file1 을 open CFileException e; if(!file1.open("test1.txt", CFile::modeRead, &e)) return; CStdioFile file2; // 쓰기전용으로 file2를 open if(!file2.open("test2.txt", CFile::modeWrite CFile::modeCreate, 18 &e)) CStdioFile 클래스 사용예 return; CFileFind 클래스 로컬디스크에있는파일검색기능제공 주된멤버함수 FindFile 어떤이름을갖는파일찾기 IsDirectory 디렉토리인지파악 MFC 클래스계층도 CString str; // test1.txt 를 string 으로읽어들여 test2.txt 에쓴다 while(file1.readstring(str)) str.makeupper(); file2.writestring(str + "\n"); 19 20
CFileFind 클래스 사용예 현재디렉토리에대한모든파일과디렉토리를보여주는예제 void CExFileView::OnLButtonDblClk(UINT nflags, CPoint point) CFileFind finder; BOOL bworking = finder.findfile("*.*"); while(bworking) bworking = finder.findnextfile(); if(finder.isdirectory()) TRACE("[%s]\n", (LPCTSTR)finder.GetFileName()); else TRACE("%s\n", (LPCTSTR)finder.GetFileName()); 도큐먼트 / 뷰구조 개념 프로그램에서사용할데이터를관리하는부분과이데이터를실제로화면에표시하는부분을서로다른모듈로구현한다 Document 데이터관리에해당하는기능을구현하는클래스 View 데이터를화면에표시하는기능을구현하는클래스 21 22 도큐먼트 / 뷰구조 디스크에저장된파일을읽는경우 도큐먼트객체가파일에저장된데이터를읽은후 뷰객체로하여금데이터를화면에보이게한다 도큐먼트 / 뷰구조 사용자가키보드 / 마우스로데이터를입력하는경우 뷰가처리한후 입력된데이터를도큐먼트객체에저장 도큐먼트객체 도큐먼트객체 파일 뷰객체 사용자 파일 뷰객체 사용자 23 24
도큐먼트 / 뷰구조 입력된문서를디스크파일로저장하는경우 저장된명령을내리면 도큐먼트객체가자신이유지하는데이터를디스크파일로저장 도큐먼트 / 뷰구조 도큐먼트와뷰클래스의역할클래스역할 도큐먼트객체 도큐먼트 데이터를저장하거나읽어들인다. 데이터의변경사항이생기면뷰의화면을갱신한다. 파일 뷰객체 사용자 뷰 데이터를화면에표시한다. 사용자와의상호작용을담당한다. 25 26 도큐먼트 / 뷰구조 도큐먼트 / 뷰구조의장점 서로다른기능을도큐먼트와뷰클래스로분리해서구현하기때문에개념적으로이해하기쉽다. 하나의도큐먼트에여러개의뷰가존재하는모델을구현하기가쉽다. 예 ) 비주얼 C++ 편집창 MFC 에서도큐먼트 / 뷰구조를위해제공하는부가적인서비스를이용할수있다. 예 ) 직렬화 도큐먼트 / 뷰구조 SDI 와 MDI 다룰수있는문서의개수에따라구분 27 28
도큐먼트 / 뷰구조 도큐먼트템플릿 도큐먼트 / 뷰구조의핵심적인클래스 도큐먼트, 프레임윈도우, 뷰클래스정보를유지 필요에따라해당객체를동적으로생성 MFC 클래스계층도 SDI MDI 29 도큐먼트 / 뷰구조 InitInstance() 함수 템플렛객체를동적으로생성한후 응용프로그램에등록 BOOL CExFileApp::InitInstance() CSingleDocTemplate* pdoctemplate; // 도큐먼트, 프레임, 뷰를가지고있는템플렛객체생성 pdoctemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CExFileDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CExFileView)); AddDocTemplate(pDocTemplate); // 응용프로그램에등록 30 도큐먼트 / 뷰구조 주요객체의관계 도큐먼트 / 뷰구조응용프로그램예제작성 프로젝트생성 생성주체 1응용프로그램객체도큐먼트템플릿객체프레임윈도우객체 생성되는것 2도큐먼트템플릿객체 3도큐먼트객체, 4프레임윈도우객체 5뷰객체 31 32
도큐먼트 / 뷰구조응용프로그램예제작성 1~6 단계옵션설정 도큐먼트 / 뷰구조응용프로그램예제작성 코드추가 단계변경사항 1 'Single document' 를선택한다. 2 Compound Document Support 변경사항없음 3 DB 변경사항없음 4 UI 변경사항없음 5 Advanced Features 'ActiveX Controls' 선택을해제한다. 6 Generated Classes 변경사항없음 void CExFileView::OnDraw(CDC* pdc) CExFileDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); pdc->setmapmode(mm_lometric); pdc->ellipse(100, -100, 600, -600); // 그림을추가한다 33 34 도큐먼트 / 뷰구조응용프로그램예제작성 실행결과 도큐먼트 / 뷰구조응용프로그램예제작성 실행결과 35 36
도큐먼트 / 뷰구조응용프로그램예제분석 응용프로그램클래스 1 메뉴명령핸들러 [File->New, Open, Print 등 ] BEGIN_MESSAGE_MAP(CExFileApp, CWinApp) //AFX_MSG_MAP(CExFileApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) //AFX_MSG_MAP 1 ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) END_MESSAGE_MAP() BOOL CExFileApp::InitInstance() 2 document template 객체를 동적으로생성후 2 CSingleDocTemplate* pdoctemplate; 응용프로그램객체에등록 pdoctemplate = new CSingleDocTemplate( 37 도큐먼트 / 뷰구조응용프로그램예제분석 IDR_MAINFRAME, RUNTIME_CLASS(CExFileDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CExFileView)); AddDocTemplate(pDocTemplate); 3 CCommandLineInfo cmdinfo; ParseCommandLine(cmdInfo); 4 if (!ProcessShellCommand(cmdInfo)) return FALSE; 5 m_pmainwnd->showwindow(sw_show); m_pmainwnd->updatewindow(); return TRUE; 3 명령행인자를분석후결과를 cmdinfo 에저장 4cmdInfo 에따라처리 [document, frame, view 객체가생성된다 ] 5 Frame window 가화면에보이게한후 UpdateWindow 를호출하여 WM_PAINT 가호출되게함 38 도큐먼트 / 뷰구조응용프로그램예제분석 도큐먼트 / 뷰구조응용프로그램예제분석 프레임윈도우클래스 뷰클래스 // 헤더파일 class CMainFrame : public CFrameWnd protected: 1 DECLARE_DYNCREATE(CMainFrame) // 구현파일 2 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) 39 // 헤더파일 class CExFileView : public CView protected: CExFileView(); 1 DECLARE_DYNCREATE(CExFileView) public: 2 CExFileDoc* GetDocument(); 2 3 데이터를읽어오거나저장하기위하여 document에접근해야함 #ifndef _DEBUG 3 inline CExFileDoc* CExFileView::GetDocument() return (CExFileDoc*)m_pDocument; #endif 1 동적객체생성기능을지원 - CDocument type의포인터 40 - 언제든지뷰에서 document를참조할수있게함
도큐먼트 / 뷰구조응용프로그램예제분석 도큐먼트 / 뷰구조응용프로그램예제분석 4 동적객체생성기능을지원 // 구현파일 4 IMPLEMENT_DYNCREATE(CExFileView, CView) BEGIN_MESSAGE_MAP(CExFileView, CView) //AFX_MSG_MAP(CExFileView) //AFX_MSG_MAP 5 인쇄, 미리보기기능을기본적으로제공 5 ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() 41 6 void CExFileView::OnDraw(CDC* pdc) CExFileDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); pdc->setmapmode(mm_lometric); pdc->ellipse(100, -100, 600, -600); 7 CExFileDoc* CExFileView::GetDocument() 6 OnPaint() 대신여기서는 OnDraw() 사용여기서는 Device Context 객체를생성할필요가없다. 화면출력뿐아니라, 인쇄 / 미리보기에사용 7 디버그버전으로컴파일할때사용됨 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CExFileDoc))); return (CExFileDoc*)m_pDocument; 42 도큐먼트 / 뷰구조응용프로그램예제분석 도큐먼트클래스 // 헤더파일 class CExFileDoc : public CDocument protected: CExFileDoc(); 1 DECLARE_DYNCREATE(CExFileDoc) // ClassWizard generated virtual function overrides //AFX_VIRTUAL(CExFileDoc) public: 2 virtual BOOL OnNewDocument(); 3 virtual void Serialize(CArchive& ar); //AFX_VIRTUAL 43 도큐먼트 / 뷰구조응용프로그램예제분석 public: virtual ~CExFileDoc(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif ; DECLARE_MESSAGE_MAP() // 구현파일 4 IMPLEMENT_DYNCREATE(CExFileDoc, CDocument) BEGIN_MESSAGE_MAP(CExFileDoc, CDocument) END_MESSAGE_MAP() 44
도큐먼트 / 뷰구조응용프로그램예제분석 도큐먼트 / 뷰구조응용프로그램예제분석 CExFileDoc::CExFileDoc() CExFileDoc::~CExFileDoc() 5 BOOL CExFileDoc::OnNewDocument() if (!CDocument::OnNewDocument()) return FALSE; return TRUE; 6 void CExFileDoc::Serialize(CArchive& ar) if (ar.isstoring()) else #ifdef _DEBUG void CExFileDoc::AssertValid() const CDocument::AssertValid(); void CExFileDoc::Dump(CDumpContext& dc) const CDocument::Dump(dc); #endif //_DEBUG 45 46 직렬화기초 직렬화 영속적인저장매체에객체의내용을저장하거나읽어오는과정 직렬화기초 데이터쓰기 - 일반파일입출력 CFileException e; if(!file.open("test.dat", CFile::modeReadWrite CFile::modeCreate, &e)) return int a = 100; int b = 200; file.write(&a, sizeof(a)); file.write(&b, sizeof(b)); 47 48
직렬화기초 데이터쓰기 - 직렬화 CFileException e; if(!file.open("test.dat", CFile::modeReadWrite CFile::modeCreate, &e)) return; int a = 100; int b = 200; CArchive ar (&file, CArchive::store); ar << a << b; 직렬화기초 데이터읽기 - 일반파일입출력 CFileException e; if(!file.open("test.dat", CFile::modeRead, &e)) return; int a, b; file.read(&a, sizeof(a)); file.read(&b, sizeof(b)); TRACE("a = %d, b = %d\n", a, b); 49 50 직렬화기초 데이터읽기 - 직렬화 CFileException e; if(!file.open("test.dat", CFile::modeRead, &e)) return; int a, b; CArchive ar (&file, CArchive::load); ar >> a >> b; TRACE("a = %d, b = %d\n", a, b); 직렬화기초 CArchive 클래스생성자 CArchive::CArchive (CFile* pfile, UINT nmode, int nbufsize = 4096, void* lpbuf = NULL) ; pfile CFile 객체의주소 nmode CArchive::load 또는 CArchive::store nbufsize 내부에서사용할버퍼크기 lpbuf 사용자정의버퍼의주소 51 52
직렬화기초 직렬화가능한데이터타입 직렬화기초 직렬화원리 구분 기본형 비기본형 데이터타입 BYTE, WORD, LONG, DWORD, float, double, int, short, char, wchar_t, unsigned, bool, ULONGLONG, LONGLONG RECT, POINT, SIZE, CRect, CPoint, CSize, CString, CTime, CTimeSpan, COleVariant, COleCurrency, COleDateTime, COleDataTimeSpan CArchive ar(); ar << a << b; CArchive ar(); ar >> a >> b; a, b CArchive 객체 CFile 객체 디스크파일 53 54 도큐먼트 / 뷰구조직렬화 - 파일메뉴처리기능 ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_FILE_SAVE_AS 는자동으로처리 CWinApp 에서전처리를하고 CDocument 클래스로넘긴다 ID_FILE_NEW ID_FILE_OPEN ID_FILE_SAVE ID_FILE_SAVE_AS 55 도큐먼트 / 뷰구조직렬화 - 파일메뉴처리기능 ID_FILE_NEW ID_FILE_OPEN ID_FILE_SAVE ID_FILE_SAVE_AS CWinApp 클래스 OnFileNew( ) 커맨드핸들러함수 새로운도큐먼트생성 CDocument 의멤버함수 OnNewDocument( ) 호출 OnFileOpen( ) 커맨드핸들러함수파일명을입력받음 새로운도큐먼트생성 CDocument의멤버함수 OnOpenDocument( ) 호출 OnFileSave( ) 커맨드핸들러함수처음저장하는경우 : 파일명을입력받음 CDocument 의멤버함수 OnSaveDocument( ) 호출 OnFileSaveAs( ) 커맨드핸들러함수 OnFileSave( ) 함수와같은동작 CDocument 클래스 새로운인스턴스생성됨 OnNewDocument( ) 호출됨 OnOpenDocument( ) 함수의인자로넘겨받음새로운인스턴스생성됨 OnOpenDocument( ) 호출됨 Serialize( ) 함수호출 OnSaveDocument( ) 함수의인자로넘겨받음 OnSaveDocument( ) 호출됨 Serialize( ) 함수호출 OnOpenDocument 함수와 OnSaveDocument 함수가 CArchive 객체와 CFile 객체를연결56
도큐먼트 / 뷰구조와직렬화 [ 파일 ]->[ 열기 ] 메뉴를선택한경우 ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) BOOL CDocument::OnOpenDocument(LPCTSTR lpszpathname) // CFile 객체생성. pfile 은 CFile 객체의주소값이다. CArchive ar(pfile, Archive::load CArchive::bNoFlushOnDelete); Serialize(ar) 57 도큐먼트 / 뷰구조와직렬화 [ 파일 ]->[ 저장 ] 또는 [ 다른이름으로저장 ] 메뉴를선택한경우 ON_COMMAND(ID_FILE_SAVE, OnFileSave) ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs) BOOL CDocument::OnSaveDocument(LPCTSTR lpszpathname) // CFile 객체생성. pfile 은 CFile 객체의주소값이다. CArchive ar(pfile, CArchive::store CArchive::bNoFlushOnDelete); Serialize(ar) 58 직렬화클래스구현 사용자정의클래스 class CMyData public: CString m_str; COLORREF m_color; public: CMyData(CString &str, COLORREF &color) m_str = str; m_color = color; virtual ~CMyData(); ; 직렬화클래스구현 직렬화 안됨 void CExFileDoc::Serialize(CArchive& ar) if (ar.isstoring()) ar << m_data; else ar >> m_data; 59 60
직렬화클래스구현 직렬화클래스구현 사용자정의클래스변경 사용자정의클래스변경 // 클래스선언부 class CMyData : public CObject 1 DECLARE_SERIAL(CMyData) 2 public: CString m_str; COLORREF m_color; public: CMyData() 3 CMyData(CString &str, COLORREF &color) m_str = str; m_color = color; virtual ~CMyData(); void Serialize(CArchive& ar); 4 ; 61 // 클래스구현부 CMyData::~CMyData() IMPLEMENT_SERIAL(CMyData, CObject, 1) 5 void CMyData::Serialize (CArchive& ar) 6 CObject::Serialize(ar); if(ar.isstoring()) ar << m_str << m_color; else ar >> m_str >> m_color; 62 직렬화클래스구현 CFileDialog 클래스 직렬화 사용자정의클래스의 Serialize 를사용해야함 void CExFileDoc::Serialize(CArchive& ar) if (ar.isstoring()) m_data.serialize(ar); else m_data.serialize(ar); CFileDialog 클래스의인스턴스를선언하고, DoModal 함수를호출 char szfilter[] = "Image (*.BMP, *.GIF, *.JPG) *.BMP;*.GIF;*.JPG All Files(*.*) *.* "; CFileDialog dlg(true, NULL, NULL, OFN_HIDEREADONLY, szfilter); if(idok == dlg.domodal()) CString strpathname = dlg.getpathname(); 63 64