본문 바로가기
C++, MFC

[C++/MFC] 인코딩, 유니코드 구분해서 CFile로 txt파일 읽는 방법

by dev_drive 2022. 9. 22.
반응형

인코딩 종류는 엄청 많지만 텍스트 파일을 저장할 때는 ANSI, UTF-8, UTF-8(BOM), UTF-16 LE, UTF-16 BE 이 5가지를 주로 사용합니다. 

 

 

🔽 인코딩이나 BOM에 대해 궁금하시다면 아래 글을 참고해주세요. 

 

유니코드 인코딩 BOM(Byte Order Mark) 정리

문자 인코딩(Encoding)이란? 문자 인코딩은 사용자가 입력한 문자나 기호를 컴퓨터가 이해할 수 있는 것으로 만드는 것을 의미합니다. 1. 인코딩의 종류 텍스트 파일을 저장할 때 인코딩 형식을 선

dev-drive.tistory.com

 

MFC 프로젝트에서는 멀티바이트, 유니코드 세팅을 할 수 있고 txt 파일도 여러가지 인코딩이 존재하니 이런걸 다 처리해주지 않으면 특정 경우에서는 글자가 깨질 수 있겠죠. 

-> 예를들어 멀티바이트 프로젝트에서 UTF-16파일을 읽고 후처리를 하지않으면 제대로 된 글자를 얻을 수 없습니다.  

 

 

🔽 그러면 바로 CFile로 txt파일의 인코딩을 구분해서 읽는 방법에 대해 알아보겠습니다. 

enum encoding { ANSI, UTF8, UTF8_BOM, UTF16_LE, UTF16_BE };
encoding enc = ANSI;
CString sContent; 

CString sFilePath = _T("txt파일 경로");
CFile hFile;
if (hFile.Open(sFilePath, CFile::modeRead))
{
	int nLen = (int)hFile.GetLength();
	TCHAR* pData = new TCHAR[nLen + 2];
	memset(pData, 0, (nLen + 2));

	LONG nReadSize = hFile.Read(pData, nLen);
	if (nReadSize == nLen)
	{
		// 인코딩 검사
		char* szBOM = new char[3];
		memset(szBOM, 0, 3);
		memmove(szBOM, (char*)pData, 3);
 			
		unsigned char littleEndianBOM[] = { 0xFF, 0xFE };
		unsigned char bigEndianBOM[] = { 0xFE, 0xFF };
		unsigned char utf8BOM[] = { 0xEF, 0xBB, 0xBF };
 
		unsigned char* lpHeader = (unsigned char*)szBOM;
 
		if (lpHeader[0] == littleEndianBOM[0] && lpHeader[1] == littleEndianBOM[1])
			enc = encoding::UTF16_LE;
		else if (lpHeader[0] == bigEndianBOM[0] && lpHeader[1] == bigEndianBOM[1])
			enc = encoding::UTF16_BE;
		else if (lpHeader[0] == utf8BOM[0] && lpHeader[1] == utf8BOM[1] && lpHeader[2] == utf8BOM[2])
			enc = encoding::UTF8_BOM;
		else
		{
			// 위 3가지 경우가 아닐 경우 파일 내용을 분석해 UTF8과 Ansi를 구분함
			if (IsUTF8((const void*)pData, nLen))
				enc = encoding::UTF8;
		}

		// 인코딩 처리
		WCHAR* pBuffer = new WCHAR[nLen + 2];
		memset(pBuffer, 0, nLen + 2);

		switch (enc)
		{
		case ANSI:
		{
			int nLength = MultiByteToWideChar(CP_ACP, 0, (char*)pData, nLen, NULL, NULL);
			memset(pBuffer, 0, sizeof(WCHAR)* (nLength + 1));
			MultiByteToWideChar(CP_ACP, 0, (char*)pData, nLen, pBuffer, nLength);
			break;
		}
		case UTF8:
		{
			int nLength = MultiByteToWideChar(CP_UTF8, 0, (char*)pData, nLen, NULL, NULL);
			memset(pBuffer, 0, sizeof(WCHAR)* (nLength + 1));
			MultiByteToWideChar(CP_UTF8, 0, (char*)pData, nLen, pBuffer, nLength);
			break;
		}
		case UTF8_BOM:
		{
			int nLength = MultiByteToWideChar(CP_UTF8, 0, (char*)pData + 3, nLen - 3, NULL, NULL);
			memset(pBuffer, 0, sizeof(WCHAR)* (nLength + 1));
			MultiByteToWideChar(CP_UTF8, 0, (char*)pData + 3, nLen - 3, pBuffer, nLength);
			break;
		}
		case UTF16_LE:
		{
			wcscpy_s(pBuffer, nLen + 2, (WCHAR*)pData + 1);
				break;
		}
		case UTF16_BE:
		{
			wcscpy_s(pBuffer, nLen + 2, (WCHAR*)pData + 1);
            
			// Swap Byte
			WCHAR ch;
			WCHAR* tmpBuf = new WCHAR[nLen + 2];
			memset(tmpBuf, 0, nLen + 2);
			memmove(tmpBuf, pBuffer, nLen);

			int nPos = 0;
			while (nPos <= nLen)	
			{
				ch = pBuffer[nPos];
				if (ch == 0x00)
				{
					memcpy(pBuffer, tmpBuf, nLen);
					break;
				}
				
				tmpBuf[nPos++] = MAKEWORD(HIBYTE(ch), LOBYTE(ch));
			}

			delete[] tmpBuf;
			break;
		}
		default:
			break;
		}

		sContent = (CString)pBuffer;

		delete[] szBOM;
		delete[] pData;
		delete[] pBuffer;
	}
}
hFile.Close();

* 멀티바이트, 유니코드 프로젝트 세팅과 상관 없이 모두 읽을 수 있는 소스입니다. 

* UTF-8에서 + 3, UTF-16에서 + 1 해주는 이유는 앞부분에 있는 BOM을 제외하고 읽기 위함입니다.  BOM이 필요하다면 + 부분 지우고 처리하면 됩니다.

* UTF16-BE는 Byte Order를 바꿔주기 위한 작업을 진행했습니다. 

* txt파일을 Write할때는 반대로 Byte Order를 먼저 Write하고 뒤에 내용을 넣어주면 됩니다. 

 

🔽 IsUTF8 함수에 대한 내용은 아래 글을 참고해주세요. 

 

[C++/MFC] 텍스트 파일의 인코딩 확인하는 방법

유니코드 인코딩 BOM(Byte Order Mark) 정리 문자 인코딩(Encoding)이란? 문자 인코딩은 사용자가 입력한 문자나 기호를 컴퓨터가 이해할 수 있는 것으로 만드는 것을 의미합니다. 1. 인코딩의 종류 텍스

dev-drive.tistory.com

 

 

🔽 txt파일 인코딩 구분 읽기, 쓰기 기능 추가해서 만들어본 프로그램입니다.  메모장이랑 다를게 없긴한데 필요하신분들은 다운받아서 사용하세요

CharacterEncoding.exe
3.36MB

 

반응형

댓글