1. 程式人生 > >自動將visual stdio建立的檔案從gb2312編碼轉換成utf8編碼

自動將visual stdio建立的檔案從gb2312編碼轉換成utf8編碼

cocos2d-x是一個不錯的手機遊戲框架,不過由於在中文的windows系統下使用visual stdio2008預設建立的類檔案,包括.h和.cpp,其檔案編碼都是gb2312的。當將這些檔案在cygwin上用ndk編譯時,雖然編譯沒問題,但其中的中文在讀取的時候會出現亂碼,這是cocos2d-x的一個不足,例如CCLabelTTF顯示中文的時候會出現亂碼,而且CCSpriteFrame的spriteFrameByName方法也不能傳入中文,這確實是一件頭疼的事。

解決方法有兩種,一種是將原始碼檔案儲存為utf8格式,另一種方法在使用中文字元的時候轉碼,如果使用第二種方法的,為了跨平臺,一般使用iconv這個庫進行編碼轉換。但由於iconv是基於LGPL協議,cocos2d-x已經在

最新的 cocos2d-1.0.1-x-0.12.0 release裡將iconv的靜態庫去掉了,使用其實並不建議大量頻繁地呼叫iconv進行編碼轉換,畢竟效率有所降低。

第二種方法則是將原始碼檔案編碼轉換為utf8編碼,手動的方法是在visual stdio的檔案選單裡有一個高階儲存選項,將編碼設為Unicode(UTF8帶簽名)然後儲存即可,不過這種方法比較笨,純粹是體力活。我研究過打算修改一下visual stdio的類嚮導,想把類嚮導建立的檔案修改為utf8格式,但不得其果。如果是單純的建立.h和.cpp檔案則是可以的,方法是將Microsoft Visual Studio 9.0/VC/vcprojectitems

下的newc++file.cpp和hfile.h儲存為utf8格式,這樣每次建立新的.h和.cpp都將會是utf8格式。但一般來說都會使用類嚮導建立類檔案,所以我寫了一個小程式,可以將原始碼轉換了utf8格式。程式碼如下:

// ChangeFileEncoding.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include "ChangeFileEncoding.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 唯一的應用程式物件

CWinApp theApp;

using namespace std;

void recursiveFile(CString strFileType);
void convertGBToUTF8(CString strWritePath, const char* gb2312);

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// 初始化 MFC 並在失敗時顯示錯誤
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: 更改錯誤程式碼以符合您的需要
		_tprintf(_T("錯誤: MFC 初始化失敗\n"));
		nRetCode = 1;
	}
	else
	{
		/*for(int i = 0; i < argc; i++)
		{
			MessageBox(NULL, argv[i], L"Arglist contents", MB_OK);
		}*/
		//宣告一個CFileFind類變數,以用來搜尋
		
		//接受一個引數作為原始碼檔案的根目錄
		TCHAR *lpszDirName = argv[1];
		CString strFileType;
		strFileType.Format(_T("%s\\*.*"), lpszDirName);
		//遞迴此目錄下的.h檔案和.cpp檔案,如果發現不是utf8編碼則轉換為utf8編碼
		recursiveFile(strFileType);
		
	}

	return nRetCode;
}

void recursiveFile( CString strFileType)
{
	CFileFind finder; 
	BOOL isFinded = finder.FindFile(strFileType);//查詢第一個檔案
	while(isFinded)
	{
		isFinded = finder.FindNextFile(); //遞迴搜尋其他的檔案
		if(!finder.IsDots()) //如果不是"."目錄
		{
			CString strFoundFile = finder.GetFilePath(); 
			if(finder.IsDirectory()) //如果是目錄,則遞迴地呼叫
			{ 
				CString strNextFileType;
				strNextFileType.Format(_T("%s\\*.*"), strFoundFile);
				recursiveFile(strNextFileType);
			}
			else
			{ 
				//如果是標頭檔案或cpp檔案
				if(strFoundFile.Right(4) == _T(".cpp") || strFoundFile.Right(2) == _T(".h")) {
					CFile fileReader(strFoundFile, CFile::modeRead);
					byte head[3];
					fileReader.Read(head, 3); 
					//判斷是否帶有BOM檔案頭
					if(head[0] == 0xef && head[1]==0xbb && head[2] == 0xbf )
					{
						fileReader.Close();
						continue;
					}
					fileReader.SeekToBegin();
					
					int bufLength = 256;
					char *buf = new char[bufLength];
					ZeroMemory(buf, bufLength);
					int nReadLength;
					std::string strContent;
					while((nReadLength = fileReader.Read(buf, bufLength)))
					{
						strContent.append(buf, nReadLength);
						ZeroMemory(buf, nReadLength);
					}
					delete buf; 
					fileReader.Close();
					convertGBToUTF8(strFoundFile, strContent.c_str());
				}
			}
		}
	}
	finder.Close();
}

void convertGBToUTF8(CString strWritePath, const char* gb2312)
{
	CFile fp;
	fp.Open(strWritePath, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary,NULL);
	int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len+1];
	memset(wstr, 0, len+1);
	MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len+1];
	memset(str, 0, len+1);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
	if(wstr) delete[] wstr;
	str[len] = '\n';
	const unsigned char aryBOM[]  = {0xEF, 0xBB, 0xBF};
	fp.Write(aryBOM, sizeof(aryBOM));
	fp.Write(str,len);
	delete[] str;
	fp.Close();
} 

編碼生成ChangeFileEncoding.exe後,將ChangeFileEncoding.exe放在cocos2d-x的主程式專案的根目錄下里,例如專案的目錄樹如下:

Project

----------\cocos2dx

----------\CocosDenshion

----------\Box2D

----------\MainApplication

這裡MainApplication就是主程式專案,將ChangeFileEncoding.exe放在此目錄下,然後設定MainApplication的專案屬性,在"生成事件" --"預生成事件" --"命令列"裡填入“ChangeFileEncoding.exe ./Classes”即可。這樣每次新增的檔案雖然是gb2312編碼,但每次在編譯前會自動轉換成utf8編碼。

需要原始碼的請留下郵箱。