Visual Studio 2012에서 기본 파일 형식을 UTF-8로 바꾸기

BS는 UTF-8 형식으로 .h나 .cpp와 같은 소스파일이 생성되길 희망했습니다.

그런데 바보 멍청이 Visual Studio 2012는 기본 인코딩을 사용자가 설정할 수 없게 되어 있습니다.

editorconfig.org의 도구를 사용해도 안되고…

어떤 방법으로도 기본 인코딩을 쉽게 수정할 수 없었습니다.

물론 플러그인을 만들어서 가능할 수도 있을테지만…

시간이 없네요.

그래서 일단 시도하는 방법을 소개합니다.

  1. Windows 탐색기에서 텍스트 파일 만들 때에 UTF-8로 인코딩
    위에 있는 NullFile 이름을 FileName으로 바꿉니다.
    그리고 특정 위치에 UTF-8로 인코딩된 빈 파일(즉, BOM만 있는 UTF-8파일)을 지정합니다.
    탐색기에서 새로운 텍스트 파일을 만들면

    이렇게 UTF-8 (BOM 있는) 형식으로 생성되는 걸 볼 수 있습니다.
  2. Visual Studio 2012에서 새 .h, .cpp 파일 만들 때
    C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcprojectitems
    위 경로에 가면

    위와 같이 hfile.h와 newc++file.cpp 두개 파일이 보입니다. 이 파일들을 수정해서 UTF-8 형식으로 저장합니다.
    여기에 추가로 살짝 보이는 Utility 폴더에 들어가면 text.txt가 있습니다.
    이것도 바꿉니다.
여기까지의 내용을 테스트 해봅시다.
Visual Studio 2012 IDE를 띄우고 파일 > 새로 만들기 > 파일 메뉴를 선택해서
위에서 만든 3 종류, .txt, .h, .cpp를 각각 생성해서 저장합니다.
그리고 notepad++과 같은 에디터를 통해서 확인해 보면 됩니다.
이렇게 해보면 .txt만 안되는데요.
실제 프로젝트나 솔루션에서 새 항목 추가를 통해 유틸리티 하위의 텍스트 파일을 생성하면… 이건 됩니다.

boost를 사용해서 UTF-8로 텍스트 파일을 다루기

이런 저런 이유로 대부분 UTF-8 텍스트 파일을 많이 사용하게 됩니다.


그런데 C++, 특히 Windows 환경에서는 참으로 불편하기 짝이 없습니다.


그래서 아래와 같은 방법을 사용하게 되었습니다.


// 테스트 파일명은 test.txt
std::wstring filename(L"test.txt");

// 파일을 열고
// (BS만의 다른 이유로 생성자를 통해 열지 않고 open() 메서드를 사용했습니다.)
boost::filesystem::wofstream ofs;
ofs.open(boost::filesystem::wpath(filename));

// UTF-8 BOM을 남기고
ofs << (wchar_t)0xef;
ofs << (wchar_t)0xbb;
ofs << (wchar_t)0xbf;

// 로케일 설정
std::locale loc = boost::locale::generator()("ko_KR.UTF-8");
ofs.imbue(loc);

// 쓰기
ofs << L"하하하" << std::endl;

// 닫기
ofs.close();

// 파일을 열고
boost::filesystem::wifstream ifs;
ifs.open(boost::filesystem::wpath(filename));

// 로케일 설정하고
ifs.imbue(loc);

// 읽어 봅시다
std::wstring result;
ifs >> result;


잘 되네요… 하하.. boost 최고!


그런데 수동으로 넣어줘야 했던 내 BOM은 읽을 때에 어디갔니?

boost property_tree로 UTF-8로 인코딩된 xml 읽고 쓰기

업데이트 2013-10-22) 좀 더 보기 좋은 방법을 추가했습니다.


BS가 간단한 유틸을 만들면서 설정파일을 매번 INI 형식을 사용하다가 이번에는 xml을 사용하였습니다.
사용한 라이브러리는 boost의 property tree
그런데 이렇게 무심코 사용했더니…


xml 헤더에는 인코딩이 utf-8이라고 나오지만 실제로는 Codepage 949의 ANSI 파일로 저장되네요.


그래서 UTF-8로 저장하기 위해서 아래와 같은 방법을 사용했습니다.

// 읽기
std::wstringstream ws;
ws.imbue(std::locale(std::locale::classic(), ".OCP", std::locale::ctype | std::locale::collate));
FILE* fp = nullptr;
if (_wfopen_s(&fp, _filepath.c_str(), L"rt, ccs=UTF-8") != 0)
	return false;
wchar_t buf[1024];
while (fgetws(buf, 1024, fp) != nullptr)
{
	ws << buf;
}
fclose(fp);
ws.seekg(0);
boost::property_tree::xml_parser::read_xml(ws, _settings, boost::property_tree::xml_parser::trim_whitespace);

// 쓰기
std::wostringstream wos;
wos.imbue(std::locale(std::locale::classic(), ".OCP", std::locale::ctype | std::locale::collate));
boost::property_tree::xml_parser::write_xml(wos, _settings, boost::property_tree::xml_writer_make_settings(L'\t', 1));
FILE* fp = nullptr;
if (_wfopen_s(&fp, _filepath.c_str(), L"wt, ccs=UTF-8") != 0)
	return;
fputws(wos.str().c_str(), fp);
fclose(fp);

메모리 상에서는 UCS16-LE로 하고 파일 입출력은 UTF-8로 하였습니다.
Windows에서 setlocale()이 UTF-8을 지원하면 저렇게 안해도 될텐데 말이죠…


좀 보기 안 좋습니다.


그래서 아래처럼 해봤습니다.


잘 되네요. (읽기는… 쓰기는 테스트 안했습니다. ㅎㅎㅎㅎㅎ 그냥 output stream에 L”가나다라” 했더니 BOM없는 UTF-8 문서로 저장은 잘 되네요.)

// 읽기
std::wifstream fin(_filepath.c_str());
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8<wchar_t>));
boost::property_tree::xml_parser::read_xml(fin, _settings, boost::property_tree::xml_parser::trim_whitespace);

// 쓰기
std::wofstream fout(_filepath.c_str(), new std::codecvt_utf8<wchar_t>));
boost::property_tree::xml_parser::write_xml(fout, _settings, boost::property_tree::xml_writer_make_settings(L'\t', 1));