API를 다루다 보면 UTF-16과 UTF-8, ANSI로 작성된 파일 및 문서를 실행 중에 읽어 들여야 하는 경우가 있습니다.
이때 BOM(Byte Order Mark)을 이용해 파일을 쓰거나 변환 함수를 사용해 파일을 읽어 들입니다.
제목에 나와있는 CreateFileMapping이라는 API 함수는 하드디스크에 존재하는 파일을 프로세스의 가상 메모리 공간에 연결하여 메모리처럼 읽고 쓸 수 있습니다.
흔히 사용되는 IPC 기법 중 하나인데, 포인터만으로도 파일의 내용을 바꾸거나 읽어올 수 있다는 특징을 갖고 있죠.
자세한 내용은 레퍼런스를 참고하시면 좋을 것 같습니다.
여기선 간단히 소개만 하고 일단 이 함수를 통해 UTF-8 또는 ANSI 로 작성된 파일을 Unicode(WideChar)로 변환하여 읽고 쓰는 방법에 대해서 얘기해보겠습니다.
char* ptrTemp;
TCHAR* ptrFile;
TCHAR* writeTemp;
TCHAR* readTemp[256];
HANDLE hFile, hMapp;
hFile = CreateFile(
TEXT("Hello.txt"),
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
hMapp = CreateFileMapping(
hFile,
NULL,
PAGE_READONLY,
0,0,
NULL
);
ptrFile = (TCHAR*)MapViewOfFile(hMapp, FILE_MAP_READ, 0,0,0);
위 코드는 맵 오브젝트를 만들고 주소 공간에 접근하여 파일을 읽어옵니다.
여기서 읽은 파일의 내용을 화면상에 출력하기 위해서는 UTF-16으로의 변환이 필요한데, 윈도우즈의 CP 식별자(Code Page Identifiers)에서 이 값은 1200(UTF-16)이며 전 세계 언어를 지원합니다.
참고로 한글 조합형과 완성형은 각각 1361, 949 입니다.
다음 코드를 보겠습니다.
/*
변환 함수(MultiByteToWideChar)의 세 번째 인수의 자료형이 LPCCH로 되어 있다.
하여 char* 변수를 이용해 맵 파일을 대입받고 비어있는 TCHAR 변수(readTemp)에 출력한다.
*/
ptrTemp = (char*)ptrFile;
MultiByteToWideChar(CP_UTF8, MB_RPECOMPOSED, ptrTemp, -1, readTemp, 256);
UnmapViewOfFile(ptrFile);
CloseHandle(hMapp);
CloseHandle(hFile);
일단 위와 같이 작성해서 화면에 출력해보면 정상적으로 동작합니다.
단, 출력 버퍼의 길이를 계산해서 사용해야 되며 이 기능은 위의 변환 함수(MultiByteToWideChar)가 지원하고 있습니다.
자세한 내용은 레퍼런스를 참고하시기 바랍니다.
일반적으로 UTF-8은 8bit(1byte), UTF-16은 16bit(2byte) 크기를 갖기 때문에 2배 크기로 만들어 주면 됩니다.
다음은 파일 쓰기 동작입니다.
hFile = CreateFile(
TEXT("WriteHello.txt")
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
hMapp = CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE,
0,0,
NULL
);
ptrFile = (TCHAR*)MapViewOfFile(hMapp, FILE_MAP_WRITE, 0,0,0)
읽고 쓸 수 있는 속성으로 파일을 열어 핸들을 대입받고 맵 파일을 만들어줍니다.
기본 동작은 따로 설명하지 않겠습니다.
다음 코드를 보겠습니다.
/*
BOM 설정 - Microsoft(UTF-16 BigEndian)
*/
*ptrFile = (TCHAR)0xFEFF;
writeTemp = ptrFile + 1;
wcsncpy(writeTemp, TEXT("안녕하세요"), 5);
UnmapViewOfFile(ptrFile);
CloseHandle(hMapp);
CloseHandle(hFile);
이번 글의 가장 중요한 부분입니다.
제일 먼저, 메모리 선두(*ptrFile)에 BOM(Byte Order Mark)을 설정하고 파일을 어떻게 읽고 쓸 것인지 프로그램에게 알립니다.
이후 ptrFile의 다음 번지를 writeTemp 포인터 변수로 대입받은 후 문자열을 복사해주면 파일에 쓰기 동작을 합니다.
흔히 CUI(CommandLine)에서 자주 보던 동작인데, 이처럼 분리된 공간에 저장되어 있는 파일을 프로세스의 메모리 공간에 적재한 후 포인터만으로 파일을 읽고 쓰는 동작을 할 수 있습니다.
이를 이용하면 여러 가지 유틸리티를 제작할 수 있으며 대용량 파일 복사 또는 데이터 공유 등에서도 사용할 수 있습니다.
쓸데없는 말을 넣다 보니 글이 길어졌는데, 중요한 건 프로세스 간 공유할 정보가 있다면 동일한 문자셋을 이용하고 파일을 읽고 쓸 때 BOM 설정과 함수의 도움을 받아야 된다는 것입니다.
일단 이번 글은 여기서 짧게 끝내겠습니다
감사합니다.
'컴퓨터 > C, C++' 카테고리의 다른 글
[C/C++] 문자열 검색 알고리즘 카프-라빈 (0) | 2022.11.24 |
---|---|
[C/C++] HANDLE 자료형에 대한 캐스팅 연산 (1) | 2022.10.28 |
[C/C++] 백준 1260번 C언어 (0) | 2022.09.09 |
[C/C++] 백준 7568번 C언어 (0) | 2022.06.14 |
[C/C++] 백준 2231번 C언어 (0) | 2022.06.14 |
댓글