http://blog.naver.com/PostView.nhn?blogId=hot2364928&logNo=60162315294

1. 기본적인 파일 처리 함수들

우리는 ANSI 표준 파일 관련 함수를 알고 있다. 그렇다면, Windows 파일 입,출력 함수를 알아야 할까?

Windows 에서 제공하는 파일 관련 시스템 함수는 많은 기능을 제공한다.

단순히 파일에 데이터를 읽고 쓰는 것이 전부라면, ANSI 표준 함수의 선택이 호환성에서 더 좋다.

HANDLE CreateFile(

LPCWSTR lpFileName,

DWORD dwDesiredAccess,

DWORD dwShareMode,

LPSECURITY_ATTRIBUTES lpSecurityAttributes,

DWORD dwCreationDisposition,

DWORD dwFlagsAndAttributes,

HANDLE hTemplateFile

);

첫 번째 인자는 개방할 파일 이름이다.

두 번째 인자는 읽기/쓰기 모드 지정이다. OR 연산으로 결합 가능하다.

GENERIC_READ 읽기 모드 지정

GENERIC_WRITE 쓰기 모드 지정

세 번째 인자는 파일 공유 방식을 지정한다.

0 다른 프로세스에 절대 공유 불가! 이미 개방된 파일은 중복 개방 불가.

FILE_SHARE_READ 다른 프로세스에서 이 파일에 동시 읽기 접근 가능.

FILE_SHARE_WRITE 동시 쓰기 접근 가능. 단 동시에 같은 영역 사용은 피해야 함.

네 번째 인자는 보안속성이다.

다섯 번째 인자는 파일이 생성되는 방법이다.

CREATE_ALWAYS 항상 새 파일을 생성한다.

CREATE_NEW 새 파일 생성, 같은 이름의 파일이 존재하면 실패

OPEN_ALWAYS 기존 파일 개방, 없으면 새로 생성

OPEN_EXISTING 기존 파일 개방, 존재하지 않으면 함수 호출 실패

TRUNCATE_EXISTING 기존 파일의 내용 지우고 개방, 파일이 존재하지 않으면 호출 실패

여섯 번째 인자는 파일의 특성 정보이다. 둘 이상이면 OR 연산자로 지정할 수 있고, 기본적으로 FILE_ATTRIBUTE_NORMAL 값을 사용한다.

이는 말 그대로 특별한 특성없는 보통 파일임을 의미한다.

일단든 FILE_ATTRIBUTE_NORMAL 으로 사용하자.

일곱 번째 인자는 일반적으로 NULL 을 전달하는데, Win ME/98/95 에서는 지원하지 않기 때문이다.

파일을 종료할 때는 CloseHandle 함수를 호출하면 된다.

파일 읽기 & 쓰기와 포인터

BOOL ReadFile(

HANDLE hFile,

LPVOID lpBuffer,

DWORD nNumberOfBytesToRead,

LPDWORD lpNumberOfBytesRead,

LPOVERLAPPED lpOverlapped

);

첫 번째 인자는 데이터를 읽을 파일의 핸들이다.

두 번째 인자는 읽어 들인 데이터를 저장할 버퍼의 주소를 지정한다.

세 번째 인자는 파일로부터 읽고자 하는 데이터의 크기를 바이트 단위로 지정한다.

네 번째 인자는 실제 읽어 들인 데이터 크기를 얻기 위한 변수의 주소를 지정한다.

다섯 번째 인자는 CreateFile 함수의 dwFlagsAndAttributes 와 같이 설명한다.

BOOL WriteFile(

HANDLE hFile,

LPCVOID lpBuffer,

DWORD nNumberOfBytesToWrite,

LPDWORD lpNumberOfBytesWritten,

LPOVERLAPPED lpOverlapped

);

첫 번째 인자는 데이터를 저장할 파일의 핸들이다.

두 번째 인자는 데이터를 저장하고 있는 버퍼의 주소 이다.

세 번째 인자는 파일에 저장하고자 하는 데이터 크기를 바이트 단위로 지정한다.

네 번째 인자는 파일에 실제 저장된 데이터 크기를 얻기 위해 변수의 주소를 지정한다.

다섯 번째 인자는 CreateFile 함수의 dwFlagsAndAttributes 와 함께 설명한다.

파일을 열어서 읽고 쓰고 닫는 예제

기반은 유니코드를 기반으로 한다.

/*

UNICODE_BASE_FILE_IO.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("data.txt");

TCHAR fileData[] = _T("Just test string~");

HANDLE hFile = CreateFile(

fileName, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

if(hFile == INVALID_HANDLE_VALUE)

{

_tprintf( _T("File creation fault! \n") );

return -1;

}

DWORD numOfByteWritten = 0;

WriteFile(hFile, fileData, sizeof(fileData), &numOfByteWritten, NULL);

_tprintf(_T("Written data size: %u \n"), numOfByteWritten);

CloseHandle(hFile);

return 0;

}

/*

UNICODE_BASE_FILE_READ.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("data.txt");

TCHAR fileData[STRING_LEN];

HANDLE hFile = CreateFile(

fileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if(hFile == INVALID_HANDLE_VALUE)

{

_tprintf( _T("File open fault! \n") );

return -1;

}

DWORD numOfByteRead = 0;

ReadFile(hFile, fileData, sizeof(fileData), &numOfByteRead, NULL);

fileData[numOfByteRead/sizeof(TCHAR)] = 0;

_tprintf(_T("Read data size: %u \n"), numOfByteRead);

_tprintf(_T("Read string: %s \n"), fileData);

CloseHandle(hFile);

return 0;

}

파일의 시간 정보 얻어오기

파일에서 마우스 오른쪽 속성 에 들어가면 파일 정보 확인이 가능하다.

여기서 확인할 수 있는 가장 대표적 정보는 만든 날짜, 수정한 날짜, 엑세스 한 날짜 이다.

BOOL GetFileTime(

HANDLE hFile,

LPFILETIME lpCreationTime,

LPFILETIME lpLastAccessTime,

LPFILETIME lpLastWriteTime

);

함수를 통해서 정보를 얻을 수 있다.

첫 번째 인자는 얻을 대상 파일의 핸들이다.

두 번째 인자는 파일이 생성된 시간을 얻기 위해 FILETIME 구조체 변수의 주소값을 전달한다.

세 번째 인자는 파일의 마지막 접근 시간을 얻는다.

네 번째 인자는 파일의 마지막 데이터 갱신 시간을 얻는다.

세 인자는 NULL 값을 전달해도 된다.

typedef struct _FILETIME {

DWORD dwLowDateTime;

DWORD dwHighDateTime;

} FILETIME, *PFILETIME, *LPFILETIME;

위 멤버를 자세히 알 필요는 없고, 정보는 8바이트 자료형이고 이 구조체는 UTC 기반으로 시간을 표현한다고 알면 된다.

GetFileTIme 함수는 UTC 기반으로 시간 정보를 돌려준다.

UTC Coordinated Universal Time 의 간략한 표현으로, 세계 시간의 기준을 만들기 위해 정의된 시간이다.

1601 1 1일을 기준으로, 100 나노초 단위 기준으로 지나간 시간을 계산하는 것이다.

2012 5 13일 이라 하면, 2012.05.13 – 1601.01.01 100 나노초 단위로 환산한 값이 100나노초 이다.

UTC 는 지금까지도 오차 없이 유지되고 있다.

시간 정보를 얻는 경우 대부분 UTC 기반이다.

문제는, 현재 우리가 원하는 것은 우리가 이해할 수 있는 시간 정보이기 때문이다.

물론 원하는 타입으로 시간 정보를 변경 가능하다.

/*

FileTimeInformation.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("RealScaleViewer.exe");

TCHAR fileCreateTimeInfo[STRING_LEN];

TCHAR fileAccessTimeInfo[STRING_LEN];

TCHAR fileWriteTimeInfo[STRING_LEN];

FILETIME ftCreate, ftAccess, ftWrite;

SYSTEMTIME stCreateUTC, stCreateLocal;

SYSTEMTIME stAccessUTC, stAccessLocal;

SYSTEMTIME stWriteUTC, stWriteLocal;

HANDLE hFile = CreateFile(

fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if(hFile == INVALID_HANDLE_VALUE)

{

_tprintf( _T("File open fault! \n") );

return -1;

}

// 파일 정보 추출

if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))

{

_tprintf( _T("GetFileTime function call fault! \n") );

return FALSE;

}

FileTimeToSystemTime(&ftCreate, &stCreateUTC);

SystemTimeToTzSpecificLocalTime(NULL, &stCreateUTC, &stCreateLocal);

FileTimeToSystemTime(&ftAccess, &stAccessUTC);

SystemTimeToTzSpecificLocalTime(NULL, &stAccessUTC, &stAccessLocal);

FileTimeToSystemTime(&ftWrite, &stWriteUTC);

SystemTimeToTzSpecificLocalTime(NULL, &stWriteUTC, &stWriteLocal);

_stprintf(fileCreateTimeInfo, _T("%02d/%02d/%d %02d:%02d"),

stCreateLocal.wMonth, stCreateLocal.wDay, stCreateLocal.wYear,

stCreateLocal.wHour, stCreateLocal.wMinute);

_stprintf(fileAccessTimeInfo, _T("%02d/%02d/%d %02d:%02d"),

stAccessLocal.wMonth, stAccessLocal.wDay, stAccessLocal.wYear,

stAccessLocal.wHour, stAccessLocal.wMinute);

_stprintf(fileWriteTimeInfo, _T("%02d/%02d/%d %02d:%02d"),

stWriteLocal.wMonth, stWriteLocal.wDay, stWriteLocal.wYear,

stWriteLocal.wHour, stWriteLocal.wMinute);

_tprintf( _T("File created time : %s \n"), fileCreateTimeInfo );

_tprintf( _T("File accessed time : %s \n"), fileAccessTimeInfo );

_tprintf( _T("File written time : %s \n"), fileWriteTimeInfo );

CloseHandle(hFile);

return 0;

}

FileTimeToSystemTime , SystemTimeToTzSpecificLocalTime 함수 두개를 이용하면 된다.

FileTimeToSystemTime 함수는 첫 번째 인자로 전달된 파일 시간의 정보를, SYSTEMTIME 구조체의 포맷으로 변경해 채워준다. 두 번째 전달인자의 stCreateUTC SYSTEMTIME 구조체의 변수이다.

FileTimeToSystemTime 함수의 호출로 변경되는 것은 단지 포맷이고, 시간 정보는 여전히 UTC 기준이다.

typedef struct _SYSTEMTIME {

WORD wYear;

WORD wMonth;

WORD wDayOfWeek;

WORD wDay;

WORD wHour;

WORD wMinute;

WORD wSecond;

WORD wMilliseconds;

} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

SystemTimeToTzSpecificLocalTime 함수는 UTC를 지역별, 국가별 시간대로 변경하는 함수이다.

첫 번째 전달인자는 시간대에 대한 정보이다. NULL 이 전달되면 현재 시스템의 시간대 정보로, 한국 시간대 정보를 기준으로 변경된다.

두 번째 인자는 대상이 되는 UTC 기반 시간 정보이고 세 번째 인자는 변환된 시간 정보가 채워질 변수의 주소값이다.

SetFileTime 함수를 이용해서 파일의 시간 정보를 변경할 수도 있다.

파일 사이즈 얻어오기

ANSI 표준에서는 fseek, ftell 함수를 이용해서 얻어왔다.

fseek 함수로 파일 포인터를 끝으로 이동시키고, ftell 함수로 현재 위치 정보를 얻어오는 방식이다.

Windows 에서는 GetFileSize 함수를 이용해 파일 크기를 직접 계산해 반환하는 함수를 제공한다.

첫 번째 인자는 핸들이다.

이 함수의 반환값은 DWORD 4바이트다. 따라서 4G 이상의 파일 크기를 반환값으로 얻지 못한다.

4G 이상 되는 파일을 크기를 얻을 때 사용하는 것이 두 번째 인자로, 4G 가 넘는 파일의 상위 4바이트 정보를 얻는다.

이것이 불편하면, GetFileSizeEx 함수를 사용하면 된다.

첫 번째 인자는 핸들이다.

두 번째 인자는 파일 크기를 저장 할 포인터를 인자로 전달한다.

PLARGE_INTEGER LARGE_INTEGER 의 포인터 타입이고, 8바이트 자료형이다.

/*

GetFileSize.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("RealScaleViewer.exe");

HANDLE hFile = CreateFile(

fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if(hFile == INVALID_HANDLE_VALUE)

{

_tprintf( _T("File open fault! \n") );

return -1;

}

DWORD high4ByteFileSize = 0;

DWORD low4ByteFileSize = GetFileSize(hFile, &high4ByteFileSize);

_tprintf( _T("High 4byte file size: %u byte \n"), high4ByteFileSize );

_tprintf( _T("Low 4byte file size: %u byte \n"), low4ByteFileSize );

LARGE_INTEGER fileSize;

GetFileSizeEx(hFile, &fileSize);

_tprintf( _T("Total file size: %u byte \n"), fileSize.QuadPart);

CloseHandle(hFile);

return 0;

}

GetFileSIzeEx 함수는 Win2000 , Win XP 이상에서만 지원되는 함수로, 호환성을 위해서는 GetFileSize 함수를 활용하는게 좋다.

파일의 특성(Attribute) 정보 얻어오기

파일에는 읽기 전용 , 숨김 , 보관 특성을 가지고 있다.

GetFileAttributes 함수를 이용해 받아올 수 있다.

인자는 파일 이름 넘겨주고, DWORD 형 반환값을 받는다.

비트 단위로 의미가 부여되어 있다.

오른쪽부터 첫 번째 비트가 1이면 읽기 전용 특성이다.

두 번째 비트가 1일 경우 숨김 특성을 정의한다.

#define FILE_ATTRIBUTE_READONLY 0x00000001

#define FILE_ATTRIBUTE_HIDDEN 0x00000002

라고 정의까지 되어 있다.

지금까지 두 가지 정보만 언급했는데, 파일이 가질 수 있는 특성 정보의 종류로는 12가지 정도가 더 된다.

MSDN 을 참고하면 된다.

(http://msdn.microsoft.com/ko-kr/library/aa915578.aspx)

SetFileAttributes 함수를 사용하여 변경할 수 있다.

첫 번째 인자는 파일의 이름이다.

두 번째 인자는 DWORD 형으로 변경할 특성 정보를 전달한다.

/*

Set_Get_FileAttributes.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

void ShowAttributes(DWORD attrib);

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("RealScaleViewer.exe");

_tprintf( _T("Original file attributes \n") );

DWORD attrib = GetFileAttributes( _T("RealScaleViewer.exe") );

ShowAttributes(attrib);

attrib |= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);

SetFileAttributes( _T("RealScaleViewer.exe"), attrib);

_tprintf( _T("Changed file attributes \n") );

attrib = GetFileAttributes( _T("RealScaleViewer.exe") );

ShowAttributes(attrib);

return 0;

}

void ShowAttributes(DWORD attrib)

{

/* FILE_ATTRIBUTE_NORMAL 다른 특성이 없음을 의미하므로

이어서 바로 함수를 빠져나온다 */

if(attrib & FILE_ATTRIBUTE_NORMAL)

{

_tprintf( _T("Normal \n") );

}

else

{

if(attrib & FILE_ATTRIBUTE_READONLY)

_tprintf( _T("Read Only \n") );

if(attrib & FILE_ATTRIBUTE_HIDDEN)

_tprintf( _T("Hidden \n") );

}

_tprintf( _T("\n") );

}

두 함수의 특징은 파일 핸들을 필요로 하지 않고, 대신 위치 경로를 넘겨준다.

파일의 특성(Attribute) 정보 핸들로부터 얻어오기 + a

GetFileInformationByHandle

함수가 있다.

첫 번째 인자로 핸들을 넘겨준다.

두 번쨰 인자는 LPBY_HANDLE_FILE_INFORMATION 구조체를 넘겨준다.

이 함수에서 얻는 것은 파일 특성 정보 뿐 아니라, 시간 정보, 파일 크기를 비롯한 추가적인 것들 것 얻을 수 있다.

typedef struct _BY_HANDLE_FILE_INFORMATION {

DWORD dwFileAttributes;

FILETIME ftCreationTime;

FILETIME ftLastAccessTime;

FILETIME ftLastWriteTime;

DWORD dwVolumeSerialNumber;

DWORD nFileSizeHigh;

DWORD nFileSizeLow;

DWORD nNumberOfLinks;

DWORD nFileIndexHigh;

DWORD nFileIndexLow;

} BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION;

사용 예제를 보자

/*

GetFileInfomationByHandle.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

void ShowAttributes(DWORD attrib);

void ShowFileTime(FILETIME t);

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("RealScaleViewer.exe");

BY_HANDLE_FILE_INFORMATION fileInfo;

HANDLE hFile = CreateFile(

fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if(hFile == INVALID_HANDLE_VALUE)

{

_tprintf( _T("File open fault! \n") );

return -1;

}

GetFileInformationByHandle(hFile, &fileInfo);

ShowAttributes(fileInfo.dwFileAttributes);

/****** Additional information ******************/

_tprintf( _T("File size: %u \n"), fileInfo.nFileSizeLow);

_tprintf( _T("File created time : "));

ShowFileTime(fileInfo.ftCreationTime);

_tprintf( _T("File accessed time: "));

ShowFileTime(fileInfo.ftLastAccessTime);

_tprintf( _T("File written time : "));

ShowFileTime(fileInfo.ftLastWriteTime);

return 0;

}

void ShowAttributes(DWORD attrib)

{

*/

if(attrib & FILE_ATTRIBUTE_NORMAL)

{

_tprintf( _T("Normal \n") );

}

else

{

if(attrib & FILE_ATTRIBUTE_READONLY)

_tprintf( _T("Read Only \n") );

if(attrib & FILE_ATTRIBUTE_HIDDEN)

_tprintf( _T("Hidden \n") );

}

_tprintf( _T("\n") );

}

void ShowFileTime(FILETIME t)

{

TCHAR fileTimeInfo[STRING_LEN];

FILETIME ft = t;

SYSTEMTIME stUTC, stLocal;

FileTimeToSystemTime(&ft, &stUTC);

SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

_stprintf(

fileTimeInfo, _T("%02d/%02d/%d %02d:%02d"),

stLocal.wMonth, stLocal.wDay, stLocal.wYear,

stLocal.wHour, stLocal.wMinute

);

_tprintf( _T("[%s] \n"), fileTimeInfo);

}

파일의 경로(Path) 정보 얻어오기

파일 경로를 얻어오는 함수는 GetFullPathName 이다.

첫 번째 인자는 완전경로를 확인하고자 하는 파일 이름이다.

두 번째 인자는 완전경로를 저장할 버퍼에 저장 가능한 문자열 길이이다. 바이트 단위가 아니라, 문자열 길이이다.

세 번째 인자는 완전경로를 저장할 버퍼의 주소값이다.

네 번째 인자는 완전경로가 문자열로 버퍼에 저장된 이후, 버퍼의 특정 위치를 가리키는 포인터 값이 저장된다.

/*

GetFullPathName.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("RealScaleViewer.exe");

TCHAR fileFullPathName[STRING_LEN];

LPTSTR filePtr;

GetFullPathName(fileName, STRING_LEN, fileFullPathName, &filePtr);

_tprintf( _T("%s \n"), fileFullPathName);

_tprintf( _T("%s \n"), filePtr);

return 0;

}

이 예제의 실행결과로 함수의 네 번째 인자가 어디까지를 가리키는 지 알 수 있다.

파일 포인터의 이동 - 32비트 기반

ANSI 표준 함수 fseek 함수에 해당하는 Windows 시스템 함수는 SetFilePointer 이다.

이 것은 fseek 함수를 잘 알고 있다는 가정 하에 설명하겠다.

DWORD SetFilePointer(

HANDLE hFile,

LONG lDistanceToMove,

PLONG lpDistanceToMoveHigh,

DWORD dwMoveMethod

);

첫 번째 인자는 파일 포인터 위치를 이동시킬 대상 파일의 핸들이다.

두 번째 인자는 이동시킬 거리다. 만약 64비트 기반이면 하위 4바이트 정보를 표현한다.

세 번째 인자는 64비트 기반 대용량 파일에서만 의미를 지닌다. 상위 4바이트 정보를 표현하는데, 32비트 기반에서는 NULL을 전달한다.

네 번째 인자는 파일 포인터 이동 시 기준이 되는 위치이다.

파일의 가장 앞부분을 기준으로 하려면 FILE_BEGIN 이다. fseek 함수의 SEEK_SET 이다.

파일 포인터의 현재 위치를 기준으로 하면 FILE_CURRENT 가 인자이고, fseek 함수의 SEEK_CUR이다.

파일의 마지막 부분이면 FILE_END 이고, fseek 함수의 SEEK_END 에 해당한다.

32비트에서 4G 가 넘지 않는 파일을 다룰 때, 예제를 보자.

/*

SetFilePointer_32BIT_VERSION.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

TCHAR fileData[] = _T("abcdefghijklmnopqrstuvwxyz");

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("abcd.dat");

TCHAR readBuf[STRING_LEN];

HANDLE hFile;

DWORD numOfByteWritten = 0;

DWORD dwPtr = 0;

/*********** file write ********************/

hFile = CreateFile (

fileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);

WriteFile ( hFile, fileData, sizeof(fileData), &numOfByteWritten, NULL );

CloseHandle(hFile);

/*********** file read ********************/

hFile = CreateFile(

fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);

ReadFile(hFile, readBuf, sizeof(readBuf), &numOfByteWritten, NULL);

_tprintf( _T("%s \n"), readBuf);

/*********** 파일 포인터를 앞으로 이동 ***********/

dwPtr = SetFilePointer (hFile, sizeof(TCHAR) * 4, NULL, FILE_BEGIN) ;

if (dwPtr == INVALID_SET_FILE_POINTER)

{

_tprintf( _T("SetFilePointer Error \n") );

return -1;

}

ReadFile(hFile, readBuf, sizeof(readBuf), &numOfByteWritten, NULL);

_tprintf( _T("%s \n"), readBuf);

/*********** 파일 포인터를 뒤로 이동 ***********/

dwPtr = SetFilePointer (hFile, -(sizeof(TCHAR) * 4), NULL, FILE_END) ;

if (dwPtr == INVALID_SET_FILE_POINTER)

{

_tprintf( _T("SetFilePointer Error \n") );

return -1;

}

ReadFile(hFile, readBuf, sizeof(readBuf), &numOfByteWritten, NULL);

_tprintf( _T("%s \n"), readBuf);

CloseHandle(hFile);

return 0;

}

SetFilePointer 함수의 반환값이 INVALID_SET_FILE_POINTER 이면 오류가 발생했음을 의미한다.

#define INVALID_SET_FILE_POINTER ((DWORD)-1)

위 예제의 형태로 코드를 구현 할 때 지원하는 최대 크기는 2^32 – 2 바이트 이다.

SetFilePointer 함수 호출 성공 시 변경된 위치의 파일 포인터값을 반환한다.

물론 파일 포인터 위치 중 아래 4바이트에 해당하는 값을 반환한다.

invalid_SET_FILE_POINTER 32비트로 표현하면 0xFFFFFFFF , 10진수로 2^32 – 1 이다.

파일 크기가 정확히 4G 이고, 파일 포인터가 SetFilePointer 함수 호출로 이 파일의 끝을 가리킨다면, 2^32 -1 이 반환된다.

그런데, 2^32 -1 10진수로 -1 에 해당한다.

따라서 오류 발생 시 반환되는 INVALID_SET_FILE_POINTER 와 구분하지 못한다.

만약 파일의 크기가 딱! 4G 이라면 말이다.

이것 때문에, 32비트 기반에서 지원 가능한 최대 크기가 2^32 – 2 가 된 것이다.

파일 포인터의 이동 - 64비트 기반

/*

SetFilePointer_64BIT_VERSION.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

TCHAR fileData[] = _T("abcdefghijklmnopqrstuvwxyz");

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("abcd.dat");

TCHAR readBuf[STRING_LEN];

HANDLE hFile;

DWORD numOfByteWritten = 0;

DWORD dwPtrLow = 0;

LONG lDistanceLow = sizeof(TCHAR) * 4;

LONG lDistanceHigh = 0;

/*********** file write ********************/

hFile = CreateFile (

fileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

WriteFile ( hFile, fileData, sizeof(fileData), &numOfByteWritten, NULL );

CloseHandle(hFile);

/*********** file read ********************/

hFile = CreateFile(

fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

ReadFile(hFile, readBuf, sizeof(readBuf), &numOfByteWritten, NULL);

_tprintf( _T("%s \n"), readBuf);

/*********** 파일 포인터를 앞으로 이동 ***********/

dwPtrLow = SetFilePointer (hFile, lDistanceLow, &lDistanceHigh, FILE_BEGIN);

if ((dwPtrLow == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))

{

_tprintf( _T("SetFilePointer Error \n") );

return -1;

}

ReadFile(hFile, readBuf, sizeof(readBuf), &numOfByteWritten, NULL);

_tprintf( _T("%s \n"), readBuf);

CloseHandle(hFile);

return 0;

}

64비트 기반 오류 검사 할 때는 GetLastError() != NO_ERROR 이라는 것이 추가 되었다.

이 과정이 필요한 이유는, 파일의 위치가 2^32 – 1 의 위치에 놓일 수 있기 때문이다.

이렇게 되면 파일 포인터 위치는 0xFFFFFFFFF 가 되는데, 이것은 INVALID_SET_FILE_POINTER 와 동일하다.

2. 디렉터리 관련 함수 및 그 밖의 함수들

디렉터리의 생성과 소멸

디렉터리를 생성 하기 위해서는 CreateDirectory 함수를 사용한다.

첫 번째 인자는 디렉터리 이름이다.

두 번째 인자는 보안속성이고, 기본적으로 NULL 을 전달한다.

RemoveDirectory 함수를 이용해서 디렉터리를 소멸 할 수 있다.

인자로는 소멸하고자 하는 디렉터리 이름을 넘겨주면 된다.

/*

CreateDeleteDirectory.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define CREATE_DIRECTORY 1

int _tmain(int argc, TCHAR* argv[])

{

TCHAR dirReletivePath[] = _T("GoodDirectoryOne");

TCHAR dirFullPath[] = _T("C:\\GoodDirectoryTwo");

#if CREATE_DIRECTORY

CreateDirectory(dirReletivePath, NULL);

CreateDirectory(dirFullPath, NULL);

#else

RemoveDirectory(dirReletivePath);

RemoveDirectory(dirFullPath);

#endif

return 0;

}

예제에서 주의점은 경로를 C:\\aaa\bbb\ccc\hi 라고 해 준다해도 aaa,bbb,ccc 디렉터리가 생성되지는 않는다.

현재 디렉터리, 시스템 디렉터리 그리고 Windows 디렉터리

현재 디렉터리(Current Directory)

현재 디렉터리는 초기에는 프로그램이 로드 된 디렉터리로 설정되며, 이후 변경이 가능하다고 생각하면 된다.

현재 디렉터리가 지니는 의미는, CreateFile 함수 호출을 통해 파일 생성을 하려 할 때, 완전경로를 지정하지 않고, 그냥 파일 이름만 명시하였을 때, 기준이되는 디렉터리 이다.

디렉터리를 참조하는 함수는 GetCurrentDirectory 함수이다.

첫 번째 인자는 두 번째 인자로 전달된 버퍼의 길이이고, 두 번째 인자는 정보를 저장할 버퍼의 주소값이다.

디렉터리를 설정하는 함수는 SetCurrentDirectory 함수로, 인자는 변경하고자 하는 디렉터리 정보를 넘겨주면 된다.

/*

CurrentDirectory.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#define STRING_LEN 100

TCHAR fileData[] = _T("abcdefghijklmnopqrstuvwxyz");

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[] = _T("abcd.dat");

TCHAR readBuf[STRING_LEN];

HANDLE hFileWrite;

HANDLE hFileRead;

DWORD numOfByteWritten;

/*********** file write ********************/

hFileWrite = CreateFile (

fileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

WriteFile ( hFileWrite, fileData, sizeof(fileData), &numOfByteWritten, NULL );

CloseHandle(hFileWrite);

/* 현재 디렉터리 변경 */

SetCurrentDirectory( _T("C:\\") );

/*********** file read ********************/

hFileRead = CreateFile(

fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);

if(hFileRead == INVALID_HANDLE_VALUE)

{

_tprintf( _T("File open error! \n") );

return -1;

}

ReadFile(hFileRead, readBuf, sizeof(readBuf), &numOfByteWritten, NULL);

_tprintf( _T("%s \n"), readBuf);

CloseHandle(hFileRead);

return 0;

}

시스템 디렉터리(System Directory) & Windows 디렉터리

시스템 디렉터리는 각종 라이브러리 및 드라이버 파일처럼 Windows 시스템에 중요한 파일들이 존재하는 위치이고, Windows 디렉터리는 초기화 및 실행파일들이 존재하는 위치이다.

그리고, 이런 디렉터리들은 변경이 불가능 하다. 정확히 말하면 변경하면 안된다.

시스템 디렉터리를 받는 함수는 GetSystemDirectory 이다.

첫 번째 인자는 디렉터리 정보를 저장할 버퍼의 주소값이고, 두 번쨰 인자는 그 버퍼의 길이이다.

GetWindowsDirectory 함수는 윈도우 디렉터리 정보를 얻어온다.

인자는 위와 동일하다.

/*

System_Windows_Dir.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

int _tmain(int argc, TCHAR* argv[])

{

TCHAR sysPathBuf[MAX_PATH];

TCHAR winPathBuf[MAX_PATH];

GetSystemDirectory(sysPathBuf, MAX_PATH);

GetWindowsDirectory(winPathBuf, MAX_PATH);

_tprintf( _T("System dir: %s \n"), sysPathBuf);

_tprintf( _T("Windows dir: %s \n"), winPathBuf);

return 0;

}

MAX_PATH windef.h #define MAX_PATH 260 으로 정의되어 있다.

디렉터리에서 파일 찾기

DWORD SearchPath(

LPCWSTR lpPath,

LPCWSTR lpFileName,

LPCWSTR lpExtension,

DWORD nBufferLength,

LPWSTR lpBuffer,

LPWSTR *lpFilePart

);

함수로 특정 디렉터리 내에 존재하는 파일 정보를 얻는다.

첫 번째 인자는 대상 경로이고, NULL 이 전달되면 표준 검색경로로 검색이 된다.

1. 실행 중인 프로그램이 로드 된 디렉터리

2. 현재 디렉터리

3. 시스템 디렉터리

4. Windows 디렉터리

5. 마지막으로 환경변수 PATH에 등록된 디렉터리들

두 번째 인자는 찾고자 하는 파일 이름이다.

세 번째 인자는 확장자로 첫 번째 문자는 반드시 . 으로 시작해야 한다. 두 번째 인자가 확장자를 포함하거나, 확장자가 필요없으면 NULL 을 넣어준다.

네 번째 인자는 완전 경로명을 저장할 버퍼의 길이이다.

다섯 번째 인자는 완전경로명을 저장할 버퍼의 주소이다.

여섯 번째 인자는 함수 호출 결과로 얻게 될 완전경로명의 마지막의 파일 이름의 위치정보를 얻게 된다.

/*

SearchPath.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

int _tmain(int argc, TCHAR* argv[])

{

TCHAR fileName[MAX_PATH];

TCHAR bufFilePath[MAX_PATH];

LPTSTR lpFilePart;

DWORD result;

_tprintf( _T("Insert name of the file to find: ") );

_tscanf( _T("%s"), fileName);

result = SearchPath(NULL, fileName, NULL, MAX_PATH, bufFilePath, &lpFilePart);

if(result == 0)

{

_tprintf( _T("File not found! \n") );

}

else

{

_tprintf( _T("File path: %s \n"), bufFilePath);

_tprintf( _T("File name only: %s \n"), lpFilePart);

}

return 0;

}

예제를 실행하고 CMD.EXE 를 입력해 보길 바란다.

함수를 세 가지 더 소개한다.

먼저 FindFirstFile 함수는 첫 번째 전달인자를 통해서 전달되는 디렉터리나 파일 이름을 통해서 부합되는 파일을 찾고, 정보를 추출해서 두 번째 전달인자가 가리키는 변수에 저장하는 함수이다.

반환 타입은 HANDLE 이고, 검색을 위한 핸들이다.

이 함수를 통해서는 조건에 맞는 파일 중 가장 첫 번째 검색된 파일 정보만 얻어 온다.

그 다음 필요한 함수는 FindNextFile 함수이다.

첫 번째 인자로 FindFirstFile 함수 호출로 얻은 핸들을 전달하고, 두 번째 인자는 발견된 파일이나 정보를 담을 WIN32_FIND_DATA 구조체 변수를 전달한다.

FindFirstFile 함수는 결과적으로 커널 오브젝트를 생성한다. 따라서 검색이 끝나면 FindClose 함수를 통해서 리소스를 반환한다. 이 함수는 인자로 핸들을 받는다.

typedef struct _WIN32_FIND_DATAW {

DWORD dwFileAttributes;

FILETIME ftCreationTime;

FILETIME ftLastAccessTime;

FILETIME ftLastWriteTime;

DWORD nFileSizeHigh;

DWORD nFileSizeLow;

DWORD dwReserved0;

DWORD dwReserved1;

WCHAR cFileName[ MAX_PATH ];

WCHAR cAlternateFileName[ 14 ];

} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;

멤버 이름만 봐도 각각의 의미는 알 수 있을 것이다.

잘 모르는 멤버는 그냥 넘어가도 된다.

이제 예제를 통해 CFileName 의 정보를 출력 해 보도록 한다.

dwReserved1 은 말 그대로 예약만 되어 있을 뿐, 사용되지는 않고, dwReserved0 dwFileAttributes의 값에 따라 의미 있는 값이 채워질 수도 있다.

자세한건 MSDN 을 참고하기 바란다.

/*

ListDirectoryFileList.cpp

*/

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

int main(int argc, TCHAR* argv[])

{

WIN32_FIND_DATA FindFileData;

HANDLE hFind = INVALID_HANDLE_VALUE;

TCHAR DirSpec[MAX_PATH];

_tprintf ( _T("Insert target directory: ") );

_tscanf( _T("%s"), DirSpec);

_tcsncat (DirSpec, _T("\\*"), 3);

hFind = FindFirstFile(DirSpec, &FindFileData);

if (hFind == INVALID_HANDLE_VALUE)

{

_tprintf ( _T("Invalid file handle \n") );

return -1;

}

else

{

_tprintf ( _T("First file name is %s\n"), FindFileData.cFileName);

while (FindNextFile(hFind, &FindFileData) != 0)

_tprintf ( _T("Next file name is %s\n"), FindFileData.cFileName);

FindClose(hFind);

}

return 0;

}

\* ALL 의 의미를 내포하는 와일드카드 문자이다.

만약 exe 로 끝나는 파일만 검색하려면, *.exe 로 검색하면 된다.

3. 명령 프롬프트 프로젝트 기능 추가

이번에는 xcopy 명령어를 구현 해 보겠다. 파일 입,출력 및 디렉터리 컨트롤 관련이 아니라, 재귀가 주제이다.

xcopy의 이해

xcopy 는 디렉터리 단위 복사 기능이다.

디렉터리 안에는 파일이 존재해도 되고, 서브 디렉터리가 존재해도 된다.

xcopy xcopy ‘디렉터리A’ ‘디렉터리B’ /s 로 구성되어 있다.

디렉터리A 는 복사 대상이 되는 원본 디렉터리 정보이고, 디렉터리 B 는 복사할 위치 정보이다.

옵션 /s 는 하위 디렉터리까지 모두 복사하라는 의미이다.

xcopy 의 구현 범위 및 방법

원래 xcopy /s 가 붙는 만큼 다양한 기능을 제공하지만, 여기서는 디렉터리 복사만 가능하도록 기능을 제한한다.

모든 서브 디렉터리 구조를 복사해야 하므로, 재귀적 방법이 필요하다.

그리고 탐색을 위해, 파일인지 디렉터리 정보지 확인하기 위해, 예제들을 참고하고

구조체 WIN32_FIND_DATA의 멤버 wFileAttributes 을 통해 얻을 수 있는 정보에 대해서도 조사하기 바란다.

CopyFile 은 파일 복사를 하는 함수이다.

첫 번째 인자는 복사 대상 원본 파일 이름이고, 두 번째 인자는 복사 결과 생성될 파일 이름이다.

세 번째 인자는 TRUE 가 전달되고, 두 번째 전달인자가 지정하는 파일이 존대할 경우 함수 호출은 실패가 된다.

xcopy의 구현 사례

디렉터리를 순차적으로 검색하며, 디렉터리이면 디렉터리 생성, 파일이면 파일 복사를 반복하는 구조이다.

/*

CommandPrmpt_Seven.cpp

*/

#include <stdio.h>

#include <tchar.h>

#include <locale.h>

#include <windows.h>

#include <tlhelp32.h>

#define STR_LEN 256

#define CMD_TOKEN_NUM 10

TCHAR ERROR_CMD[]

= _T("'%s' 실행할 있는 프로그램이 아닙니다. \n");

TCHAR cmdString[STR_LEN];

TCHAR cmdTokenList[CMD_TOKEN_NUM][STR_LEN];

TCHAR seps[] = _T(" ,\t\n");

int CmdReadTokenize(void);

int CmdProcessing(int);

TCHAR * StrLower(TCHAR *);

int _tmain(int argc, TCHAR * argv[])

{

// 한글 입력을 가능케 하기 위해

_tsetlocale(LC_ALL, _T("Korean"));

if(argc > 2) // 매개 변수 전달 인자가 있는 경우

{

for(int i= 1; i<argc; i++)

_tcscpy(cmdTokenList[i-1], argv[i]);

CmdProcessing(argc-1);

}

DWORD isExit = NULL;

while(1)

{

int tokenNum = CmdReadTokenize();

if(tokenNum == 0) //Enter 입력 처리를 위해

continue;

isExit = CmdProcessing(tokenNum);

if(isExit == TRUE)

{

_fputts(_T("명령어 처리를 종료합니다. \n"), stdout );

break;

}

}

return 0;

}

int CmdReadTokenize(void)

{

TCHAR * token;

_fputts( _T("Best command prompt>> "), stdout );

_getts(cmdString);

token = _tcstok(cmdString, seps);

int tokenNum = 0;

while(token != NULL)

{

_tcscpy ( cmdTokenList[tokenNum++], StrLower(token) );

token = _tcstok(NULL, seps);

}

return tokenNum;

}

void ListProcessInfo(void)

{

HANDLE hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

if( hProcessSnap == INVALID_HANDLE_VALUE )

{

_tprintf( _T("CreateToolhelp32Snapshot error! \n") );

return;

}

PROCESSENTRY32 pe32; /* 프로세스 정보 얻기 위한 구조체 변수 */

/* PROCESSENTRY32 변수는 사용하기 전에 크기 정보 초기화 해야 한다 */

pe32.dwSize = sizeof( PROCESSENTRY32 );

/* 번째 프로세스 정보 얻음 */

if( !Process32First( hProcessSnap, &pe32 ) )

{

_tprintf( _T("Process32First error! \n") );

CloseHandle( hProcessSnap );

return;

}

do

{

/* 프로세스 이름 ID 정보 출력 */

_tprintf(_T("%25s %5d \n"), pe32.szExeFile, pe32.th32ProcessID);

} while( Process32Next( hProcessSnap, &pe32 ) );

CloseHandle( hProcessSnap );

}

void KillProcess(void)

{

HANDLE hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

if( hProcessSnap == INVALID_HANDLE_VALUE )

{

_tprintf( _T("CreateToolhelp32Snapshot (of processes)") );

return;

}

PROCESSENTRY32 pe32;

pe32.dwSize = sizeof( PROCESSENTRY32 );

if( !Process32First( hProcessSnap, &pe32 ) )

{

_tprintf( _T("Process32First") );

CloseHandle( hProcessSnap );

return;

}

HANDLE hProcess;

BOOL isKill = FALSE;

do

{

if(_tcscmp(pe32.szExeFile, cmdTokenList[1]) == 0)

{

hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );

if(hProcess != NULL)

{

TerminateProcess(hProcess, -1);

isKill = TRUE;

}

CloseHandle(hProcess);

break;

}

} while( Process32Next( hProcessSnap, &pe32 ) );

CloseHandle( hProcessSnap );

if(isKill == FALSE)

_tprintf(_T("Kill process fail, Try again! \n"));

}

void TypeTextFile(void)

{

TCHAR cmdStringWithOptions[STR_LEN]={0,};

BOOL isRun;

if(!_tcscmp(cmdTokenList[2], _T("|")) )

{

/* Create unnamed pipe */

HANDLE hReadPipe, hWritePipe;

SECURITY_ATTRIBUTES pipeSA ={

sizeof(SECURITY_ATTRIBUTES), NULL, TRUE

};

CreatePipe(&hReadPipe, &hWritePipe, &pipeSA, 0);

/* process type 위한 선언 /

STARTUPINFO siType={0,};

PROCESS_INFORMATION piType;

siType.cb=sizeof(siType);

siType.hStdInput=GetStdHandle(STD_INPUT_HANDLE);

siType.hStdError=GetStdHandle(STD_ERROR_HANDLE);

siType.hStdOutput=hWritePipe; // 출력 다이렉션

siType.dwFlags |=STARTF_USESTDHANDLES;

_tcscpy(cmdStringWithOptions, cmdTokenList[0]);

_stprintf(cmdStringWithOptions, _T("%s %s"), cmdStringWithOptions, cmdTokenList[1]);

isRun = CreateProcess(NULL, cmdStringWithOptions, NULL, NULL, TRUE, 0, NULL, NULL, &siType, &piType);

CloseHandle(piType.hThread);

CloseHandle(hWritePipe);

/* process sort 위한 선언*/

STARTUPINFO siSort={0,};

PROCESS_INFORMATION piSort;

siSort.cb=sizeof(siSort);

siSort.hStdInput=hReadPipe; // 입력 다이렉션

siSort.hStdError=GetStdHandle(STD_ERROR_HANDLE);

siSort.hStdOutput=GetStdHandle(STD_OUTPUT_HANDLE);

siSort.dwFlags |=STARTF_USESTDHANDLES;

isRun = CreateProcess(NULL, cmdTokenList[3], NULL, NULL, TRUE, 0, NULL, NULL, &siSort, &piSort);

CloseHandle(piSort.hThread);

CloseHandle(hReadPipe);

WaitForSingleObject(piType.hProcess, INFINITE);

WaitForSingleObject(piSort.hProcess, INFINITE);

CloseHandle(piType.hProcess);

CloseHandle(piSort.hProcess);

}

else

{

_tcscpy(cmdStringWithOptions, cmdTokenList[0]);

_stprintf(cmdStringWithOptions, _T("%s %s"), cmdStringWithOptions, cmdTokenList[1]);

STARTUPINFO si={0,};

PROCESS_INFORMATION pi;

si.cb=sizeof(si);

isRun = CreateProcess(NULL, cmdStringWithOptions, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

WaitForSingleObject(pi.hProcess, INFINITE);

CloseHandle(pi.hProcess);

CloseHandle(pi.hThread);

}

}

/******************************************************************

XCOPY 관련 함수 변수

******************************************************************/

int nCopyFiles = 0;

BOOL XCOPY(TCHAR * source, TCHAR * dest);

BOOL CopyDirectoryFiles(WIN32_FIND_DATA fileData, TCHAR * source, TCHAR * dest)

{

BOOL isSuccess = NULL;

if( !_tcscmp(fileData.cFileName, _T(".") ) || !_tcscmp(fileData.cFileName, _T("..")))

{

// 특별한 처리 필요 없음

}

else if(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)

{

TCHAR subSourceDir[MAX_PATH];

TCHAR subDestDir[MAX_PATH];

_stprintf(subSourceDir, _T("%s\\%s"), source, fileData.cFileName);

_stprintf(subDestDir, _T("%s\\%s"), dest, fileData.cFileName);

CreateDirectory(subDestDir, NULL);

XCOPY(subSourceDir, subDestDir);

}

else

{

TCHAR sourceFile[MAX_PATH];

TCHAR destFile[MAX_PATH];

_tcscpy(sourceFile, source);

_tcscpy(destFile, dest);

_stprintf(sourceFile, _T("%s\\%s"), sourceFile, fileData.cFileName);

_stprintf(destFile, _T("%s\\%s"), destFile, fileData.cFileName);

isSuccess = CopyFile(sourceFile, destFile, FALSE);

if(isSuccess == 0)

return FALSE;

nCopyFiles++;

}

return TRUE;

}

// Only Directory Copy!

BOOL XCOPY(TCHAR * source, TCHAR * dest)

{

// Copy Recursively...

WIN32_FIND_DATA fileData;

BOOL isSuccess = NULL;

TCHAR firstFFStr[MAX_PATH];

_stprintf(firstFFStr, _T("%s\\%s"), source, _T("*"));

HANDLE searchHandle = FindFirstFile(firstFFStr, &fileData);

if(searchHandle == INVALID_HANDLE_VALUE)

return FALSE;

else

CopyDirectoryFiles(fileData, source, dest);

while (1)

{

if (!FindNextFile(searchHandle, &fileData))

break;

else

{

isSuccess = CopyDirectoryFiles(fileData, source, dest);

if(isSuccess == FALSE)

break;

}

}

FindClose(searchHandle);

return TRUE;

}

int CmdProcessing(int tokenNum)

{

BOOL isRun;

STARTUPINFO si={0,};

PROCESS_INFORMATION pi;

TCHAR cmdStringWithOptions[STR_LEN]={0,};

TCHAR optString[STR_LEN]={0,};

si.cb=sizeof(si);

if( !_tcscmp(cmdTokenList[0],_T("exit")) )

{

return TRUE;

}

else if ( !_tcscmp(cmdTokenList[0],_T("start")) )

{

if(tokenNum >1)

{

for(int i=1; i<tokenNum; i++)

_stprintf(optString, _T("%s %s"), optString, cmdTokenList[i]);

_stprintf(cmdStringWithOptions, _T("%s %s"), _T("CmdProject.exe"), optString);

}

else

_stprintf(cmdStringWithOptions, _T("%s"), _T("CmdProject.exe"));

isRun = CreateProcess(NULL, cmdStringWithOptions, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

CloseHandle(pi.hProcess);

CloseHandle(pi.hThread);

}

else if ( !_tcscmp(cmdTokenList[0], _T("echo")) )

{

for(int i=1; i<tokenNum; i++)

_stprintf(optString, _T("%s %s"), optString, cmdTokenList[i]);

_tprintf( _T("echo message:%s \n"), optString);

}

else if( !_tcscmp(cmdTokenList[0], _T("lp")) )

{

ListProcessInfo();

}

else if( !_tcscmp(cmdTokenList[0], _T("kp")) )

{

if(tokenNum <2)

{

_tprintf(_T("usage: kp <process name> \n"));

return 0;

}

KillProcess();

}

else if( !_tcscmp(cmdTokenList[0], _T("sort")) )

{

if(!_tcscmp(cmdTokenList[1], _T(">")) )

{

SECURITY_ATTRIBUTES fileSec = {

sizeof(SECURITY_ATTRIBUTES), NULL, TRUE

};// 상속 가능해야 지정 가능!

HANDLE hFile = CreateFile (

cmdTokenList[2], GENERIC_WRITE, FILE_SHARE_READ,

&fileSec, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL

);

si.hStdOutput = hFile;

si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);

si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

si.dwFlags |= STARTF_USESTDHANDLES;

isRun = CreateProcess(NULL, cmdTokenList[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

WaitForSingleObject(pi.hProcess, INFINITE);

CloseHandle(hFile);

}

else

{

isRun = CreateProcess(NULL, cmdTokenList[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

WaitForSingleObject(pi.hProcess, INFINITE);

}

CloseHandle(pi.hProcess);

CloseHandle(pi.hThread);

}

else if( !_tcscmp(cmdTokenList[0], _T("type")) )

{

TypeTextFile();

}

else if( !_tcscmp(cmdTokenList[0], _T("xcopy")) )

{

XCOPY(cmdTokenList[1], cmdTokenList[2]);

_tprintf( _T("%d개의 파일이 복사되었습니다. \n"), nCopyFiles );

}

else

{

_tcscpy(cmdStringWithOptions, cmdTokenList[0]);

for(int i=1; i<tokenNum; i++)

_stprintf(cmdStringWithOptions, _T("%s %s"), cmdStringWithOptions, cmdTokenList[i]);

isRun = CreateProcess(NULL, cmdStringWithOptions, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

CloseHandle(pi.hProcess);

CloseHandle(pi.hThread);

if(isRun == FALSE)

_tprintf(ERROR_CMD, cmdTokenList[0]);

}

return 0;

}

TCHAR * StrLower(TCHAR *pStr)

{

TCHAR *ret = pStr;

while(*pStr)

{

if(_istupper(*pStr))

*pStr = _totlower(*pStr);

pStr++;

}

return ret;

}

/*************************************************************************************

sort 프로세스로 생성

**************************************************************************************/

#define MAX_STRING_NUM 100

#define MAX_STRING_LEN 256

void SortString() // 파이프 예제를 위해서 독립 실행 파일로 만들어야 한다

{

TCHAR stringArr[MAX_STRING_NUM][MAX_STRING_LEN];

// 콘솔로 부터 문자열을 읽어들인다.

int nStr;

for(nStr=0; nStr<MAX_STRING_NUM; nStr++)

{

TCHAR * isEOF = _fgetts(stringArr[nStr], MAX_STRING_LEN, stdin);

if(isEOF == NULL) // EOF Ctrl+Z..

break;

}

// String Bubble Sort... 성능 고려하지 않고 문자열 단위 연산

TCHAR strTemp[MAX_STRING_LEN];

for(int i=0; i<nStr; i++)

{

for(int j= nStr-1; j>i; j--)

{

if( _tcscmp(stringArr[j-1], stringArr[j]) >0 )

{

_tcscpy(strTemp, stringArr[j-1]);

_tcscpy(stringArr[j-1], stringArr[j]);

_tcscpy(stringArr[j], strTemp);

}

}

}

for(int i=0; i<nStr; i++)

_fputts(stringArr[i], stdout);

}

int _tmain_sortmain(int argc, TCHAR * argv[])

{

SortString();

return 0;

}

/*************************************************************************************

type 프로세스 생성

**************************************************************************************/

void TYPE(TCHAR * fileName) // FOR REDIRECTION...

{

static TCHAR StringBuff[1024];

FILE * filePtr = _tfopen(fileName, _T("rt"));

while(_fgetts(StringBuff, 1024, filePtr))

_fputts(StringBuff, stdout);

}

int _tmain_typemain(int argc, TCHAR * argv[])

{

if(argc <2)

return -1;

TYPE(argv[1]);

return 0;

}

Posted by wakira
,