특정 디렉터리 내에 있는 내용을 출력하는 프로그램입니다.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>

#define TYPE_FILE 1  
#define TYPE_DIR 2
#define TYPE_DOT 3

#define MAX_OPTIONS 20 
#define MAX_ARG 1000 
#define MAX_COMMAND_LINE MAX_PATH+50 
#define MAX_PATH_LONG 32767 
#define MAX_NAME 256    

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);
DWORD FileType( LPWIN32_FIND_DATA);
BOOL ProcessItem( LPWIN32_FIND_DATA, DWORD, LPBOOL);
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);

int _tmain(int argc, LPTSTR argv[])
{
 BOOL flags[MAX_OPTIONS], ok = TRUE;
 TCHAR pathName[MAX_PATH + 1] , currPath[MAX_PATH + 1], tempPath[MAX_PATH + 1];
 LPTSTR pSlash, pFileName;
 int i, fileIndex;

 fileIndex = Options(argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);

 GetCurrentDirectory(MAX_PATH, currPath);

 if( argc < fileIndex + 1)
 {
  ok = TraverseDirectory(_T("*"), MAX_OPTIONS, flags);
 }
 else 
 {
  for( i = fileIndex; i < argc; i++)
  {
   _tcscpy(pathName, argv[i]);
   _tcscpy(tempPath, argv[i]);
  
   pSlash = _tstrrchr(tempPath, '\\');

   if( pSlash != NULL )
   {
    *pSlash = '\0';
    _tcscat(tempPath, _T("\\"));
    SetCurrentDirectory(tempPath);
    pSlash = _tstrrchr(pathName, '\\');
    pFileName = pSlash + 1;
   }
   else 
   {
    pFileName = pathName;
   }

   ok = TraverseDirectory(pFileName, MAX_OPTIONS, flags) && ok;

   SetCurrentDirectory(currPath);
  }
 }
}

static BOOL TraverseDirectory(LPCTSTR pathName, DWORD numFlags, LPBOOL flags)
{
 HANDLE searchHandle;
 WIN32_FIND_DATA findData;
 BOOL recursive = flags[0];
 DWORD fType, iPass;
 TCHAR currPath[MAX_PATH + 1];

 GetCurrentDirectory(MAX_PATH, currPath);

 for( iPass = 1; iPass <= 2; iPass++)
 {
  searchHandle = FindFirstFile(pathName, &findData);

  do
  {
   fType = FileType(&findData);
   if( iPass == 1 )
   {
    ProcessItem(&findData, MAX_OPTIONS, flags);
   }

   if( fType == TYPE_DIR && iPass == 2 && recursive)
   {
    _tprintf(_T("\n%s\\%s:"), currPath, findData.cFileName);

    SetCurrentDirectory(findData.cFileName);
    TraverseDirectory(_T("*"), numFlags, flags);
    SetCurrentDirectory(_T(".."));
   }
  
  }while( FindNextFile(searchHandle, &findData));

  FindClose(searchHandle);
 }

 return TRUE;

}

static DWORD FileType(LPWIN32_FIND_DATA pFileData)
{
 BOOL isDir;
 DWORD fType;
 fType = TYPE_FILE;
 isDir =(pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 if (isDir)
  if (lstrcmp(pFileData->cFileName, _T(".")) == 0
    || lstrcmp(pFileData->cFileName, _T("..")) == 0)
   fType = TYPE_DOT;
  else fType = TYPE_DIR;
 return fType;
}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD numFlags, LPBOOL flags)
{
 const TCHAR fileTypeChar[] = {_T(' '), _T('d')};
 DWORD fType = FileType(pFileData);
 BOOL longList = flags[1];
 SYSTEMTIME lastWrite;

 if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;

 _tprintf(_T("\n"));
 if (longList) {
  _tprintf(_T("%c"), fileTypeChar[fType - 1]);
  _tprintf(_T("%10d"), pFileData->nFileSizeLow);
  FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &lastWrite);
  _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"),
    lastWrite.wMonth, lastWrite.wDay,
    lastWrite.wYear, lastWrite.wHour,
    lastWrite.wMinute, lastWrite.wSecond);
 }
 _tprintf(_T(" %s"), pFileData->cFileName);
 return TRUE;
}

DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
{
 va_list pFlagList;
 LPBOOL pFlag;
 int iFlag = 0, iArg;

 va_start (pFlagList, OptStr);

 while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL
    && iFlag < (int)_tcslen (OptStr)) {
  *pFlag = FALSE;
  for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
   *pFlag = _memtchr (argv [iArg], OptStr [iFlag],
     _tcslen (argv [iArg])) != NULL;
  iFlag++;
 }

 va_end (pFlagList);

 for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);

 return iArg;
}
출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블​

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

1. Windows 환경에서 문자열 처리 방법


  Windows 는 표준 8비트 문자(char / CHAR)와 16비트 문자( C 의 wchar_t )를 지원한다. 8비트 문자는 ASCII 라고 부르며 16비트 문자는 유니코드(Unicode) UTF-16 인코딩을 통해 지원한다.


  UTF-8 : 유니코드를 위한 가변길이 문자 인코딩 방식. 유니코드 한 문자를 표현하기 위해 1바이트에서 4바이트 까지 사용한다.

  UTF-16 : 기본 다국어 평면에 속하는 문자들은 그대로 16비트 값으로 인코딩이 되고 그 이상의 문자는 특별히 정해진 방식으로 32비트 크기로 인코딩 된다.


2. 유니코드와 ASCII 문자열 모드를 선택하여 빌드하기 위한 프로그래밍 방법


 1) 모든 문자와 문자열을 일반적 형식 TCHAR, LPTSTR, LPCTSTR을 이용해서 정의한다.

 2) 유니코드를 사용하고자 하는 경우 모든 소스 모듈에 #define UNICODE와 #define _UNICODE 를 포함시킨다. UNICODE와 _UNICODE 정의에 따라 유니코드와 ASCII 문자열이 결정된다. 이 정의는 반드시 #include <windows.h> 전에 와야 한다.

 3) 바이트 버퍼 길이 들은 sizeof(TCHAR) 를 이용해서 계산한다.

 4) <tchar.h> 에 정의된 범용 C 라이브러리 문자열 및 I/O 함수를 사용한다. _fgettc, _itot 등

 5) 상수 문자열은 다음 세가지 형태 중 하나이어야 한다.

   5.1) "이 문자열은 8비트 문자들을 사용함"

   5.2) L"이 문자열은 16비트 문자들을 사용함"

   5.3) _T("이 문자열은 전처리 구문에 따라 달라짐")

 6) 텍스트 매크로들과 범용 C 라이브러리 함수들의 정의를 위해 windows.h 다음에 tchar.h를 포함한다.


출처 : 위키백과 / Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

순차적으로 파일을 복사하는 프로그램을 다음 세가지 방식으로 구현해보겠습니다.


1. 표준 C 라이브러리를 이용

2. Windows API 를 이용

3. Windows API 인 CopyFile 를 이용


1. 표준 C 라이브러리를 이용

 

#include <stdio.h>
#include <errno.h>

#define BUF_SIZE 256

int main (int argc, char *argv [])
{
FILE *inFile, *outFile;
char rec[BUF_SIZE];
size_t bytesIn, bytesOut;
if (argc != 3) {
  fprintf (stderr, "Usage: cp file1 file2\n");
  return 1;
}

inFile = fopen (argv[1], "rb");
if (inFile == NULL) {
  perror (argv[1]);
  return 2;
}
outFile = fopen (argv[2], "wb");
if (outFile == NULL) {
  perror (argv[2]);
  fclose(inFile);
  return 3;
}

while ((bytesIn = fread (rec, 1, BUF_SIZE, inFile)) > 0) {
  bytesOut = fwrite (rec, 1, bytesIn, outFile);
  if (bytesOut != bytesIn) {
   perror ("Fatal write error.");
   fclose(inFile);
   fclose(outFile);
   return 4;
  }
}

fclose (inFile);
fclose (outFile);
return 0;
} 

 

 

  1) perror 자체는 전역 변수 errno에 접근하여 함수 호출 실패에 대한 정보를 알아낸다.

  2) IO는 동기적(synchronous)이다. 연산이 끝날 때까지 기다렸다가 다음으로 나아간다.

  3) Windows 뿐만 아니라 다른 시스템에서도 실행이 가능하다.



2. Windows API 를 이용


#include <windows.h>
#include <stdio.h>

#define BUF_SIZE 256 

int main (int argc, char * argv[])
{
 HANDLE hIn, hOut;
 DWORD nIn, nOut;
 CHAR buffer [BUF_SIZE];
 if (argc != 3) {
  fprintf (stderr, "Usage: cp file1 file2\n");
  return 1;
 }
 hIn = CreateFileA (argv[1], GENERIC_READ, FILE_SHARE_READ, NULL,
   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 if (hIn == INVALID_HANDLE_VALUE) {
  fprintf (stderr, "Cannot open input file. Error: %x\n", GetLastError ());
  return 2;
 }

 hOut = CreateFileA (argv[2], GENERIC_WRITE, 0, NULL,
   CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 if (hOut == INVALID_HANDLE_VALUE) {
  fprintf (stderr, "Cannot open output file. Error: %x\n", GetLastError ());
  CloseHandle(hIn);
  return 3;
 }
 while (ReadFile (hIn, buffer, BUF_SIZE, &nIn, NULL) && nIn > 0) {
  WriteFile (hOut, buffer, nIn, &nOut, NULL);
  if (nIn != nOut) {
   fprintf (stderr, "Fatal write error: %x\n", GetLastError ());
   CloseHandle(hIn); CloseHandle(hOut);
   return 4;
  }
 }
 CloseHandle (hIn);
 CloseHandle (hOut);
 return 0;
}

  1) ReadFile / WriteFile 함수는 BOOL 값을 돌려준다. 바이트 개수는 함수 인자를 통해 반환된다.

  2) GetLastError() 함수를 통해 시스템 오류 코드를 얻을 수 있다.

 


 

3. Windows API 인 CopyFile 를 이용

 

#include <windows.h>
#include <stdio.h>
#define BUF_SIZE 256

int main (int argc, char * argv [])
{
 if (argc != 3) {
  fprintf (stderr, "Usage: cp file1 file2\n");
  return 1;
 }
 if (!CopyFileA (argv[1], argv[2], FALSE)) {
  fprintf (stderr, "CopyFile Error: %x\n", GetLastError ());
  return 2;
 }
 return 0;
}

     1) CopyFile 함수는 파일 시간 같은 메타 데이터도 복사한다.

 


 

출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29

+ Recent posts