본문 바로가기
Programming/Tips(C++,C#)

0128 - File I/O (2) - Thread Ver.

by 곰네Zip 2009. 1. 28.

*스레드 기반으로 파일 I/O하기.
Thread에서 사용할 파일 I/O에 관한 정보구조체
typedef struct _COPY_FILE{
    TCHAR szSrcFile[MAX_PATH+_MAX_FNAME];
    TCHAR szDestFile[MAX_PATH+_MAX_FNAME];
    LPVOID pDlg;
}
 -pDlg를 넣는 이유는? WorkerThread가 실행되기 전에 Dialog를 만들어두고 그 대화상자의 주소를 넘겨주기 위해서. (ProgressBar Dialog는 Main Dialog에 속해있어야한다. Thread한테 속해있는것이 아니라.)

*Thread에서 사용할 함수
DWORD WINAPI ThreadCopyFile(LPVOID pParam){
 COPY_FILE File;
 memcpy(&File, pParam, sizeof(COPY_FILE));
 CString tmp = _T("");
 HANDLE hFileSource = NULL,hFileDest = NULL;

 DWORD dwDisplayProgressValue = 0;
 DWORD dwCurrentProgressValue = 0;
 CThreadDlg* pDlg = (CThreadDlg*)File.pDlg;

 //1. 원본파일 읽기모드 로 열기
 hFileSource = ::CreateFile(File.szSrcFile,
     GENERIC_READ, //read
     FILE_SHARE_READ, //읽기모드 공유허용
     NULL,    //보안속성없음
     OPEN_EXISTING,  //존재하는 파일 열기
     FILE_ATTRIBUTE_NORMAL,
     NULL);

 if(hFileSource == INVALID_HANDLE_VALUE){
  tmp.Format(_T("원본 파일을 여는데 실패했습니다.\nError Code [%d]"),::GetLastError());
  AfxMessageBox(tmp);
  pDlg->ShowWindow(SW_HIDE);
  return FALSE;
 }

 //2. 대상파일 쓰기모드로 열기
 hFileDest = ::CreateFile(File.szDestFile,
     GENERIC_WRITE, //쓰기모드
     0,    //공유안함
     NULL,   //보안속성없음
     CREATE_NEW,  //새로생성
     FILE_ATTRIBUTE_NORMAL,
     NULL);

 if(hFileDest == INVALID_HANDLE_VALUE){
  tmp.Format(_T("복사본 파일을 생성하는데 실패했습니다.\nError Code [%d]"),::GetLastError());
  AfxMessageBox(tmp);

  ::CloseHandle(hFileSource);
  pDlg->ShowWindow(SW_HIDE);
  return FALSE;
 }

 /*
  파일복사과정....
  src의 한 block을 dest에 write. 그리고 write하는순간 Progress를 SetPos한다.
 */

 //3. loop을 돌면서 파일내용을 복사한다.
 LARGE_INTEGER llFileSize; //DWORD두개로 값이 구성 64bit임. 이유는 고용량 하드를 인식
 llFileSize.QuadPart = 0;
 LONGLONG llTotalReadSize = 0; //64비트데이터
 DWORD  dwReadSize = 0, dwWriteSize = 0;
 BOOL  bResult = FALSE;
 BYTE  byBuffer[PAGE_SIZE];

 if(!::GetFileSizeEx(hFileSource,&llFileSize)){
  AfxMessageBox(_T("원본 파일의 크기를 알 수 없습니다."));
  ::CloseHandle(hFileSource);
  ::CloseHandle(hFileDest);
  pDlg->ShowWindow(SW_HIDE);
  return FALSE;
 }

 for(LONGLONG i = 0 ; i < llFileSize.QuadPart ; i += dwReadSize){
  if(pDlg->m_bCancel){
   break;
  }

  ::ZeroMemory(byBuffer,PAGE_SIZE);

  bResult = ::ReadFile(hFileSource,byBuffer,PAGE_SIZE,&dwReadSize,NULL);
  if( !bResult){
   tmp.Format(_T("원본 파일을 읽는 데 실패하였습니다. Error Code [%d]"),::GetLastError());
   AfxMessageBox(tmp);

   break;
  }
  //if EOF then finish loop
  else if(bResult&& dwReadSize == 0){
   break;
  }

  ///////////////////////////////////////////////////////////////////////
  //복사완료 비율계산
  llTotalReadSize += dwReadSize;
  dwCurrentProgressValue = (int)(llTotalReadSize * 100 / llFileSize.QuadPart);

  if(dwDisplayProgressValue != dwCurrentProgressValue){
   pDlg->SetPos(dwCurrentProgressValue);
   dwDisplayProgressValue =dwCurrentProgressValue;
  }
  
  if(!::WriteFile(hFileDest,byBuffer,dwReadSize,&dwWriteSize,NULL)){
   tmp.Format(_T("대상 파일을 저장하는데 실패하였습니다. Error Code [%d]"),::GetLastError());
   AfxMessageBox(tmp);
  }
 }
 if(pDlg->m_bCancel){
  AfxMessageBox(_T("Cancel Copy."));
 }else{
  AfxMessageBox(_T("Complete Copy."));
 }
 ::CloseHandle(hFileSource);
 ::CloseHandle(hFileDest);

 pDlg->ShowWindow(SW_HIDE);
 return TRUE;
}

반응형

댓글