天天看點

中文編碼轉換---6種編碼30個方向的轉換

中文編碼轉換——6種編碼30個方向的轉換

1.問題提出

    在學程式設計式時,曾經有人問過“你可以編一個記事本程式嗎?”當時很不屑一顧,但是随着學習MFC的深入,了解到記事本程式也并非易事,難點就是四種編碼之間的轉換。

對于編碼,這是一個令初學者頭疼的問題,特别是對于編碼的轉換,更是難以捉摸。筆者為了完成畢業設計中的一個編碼轉換子產品,研究了中文編碼和常見的字元集後,決定解決"記事本"程式的編碼問題,更進一步完成GB2312、Big5、GBK、Unicode 、Unicode big endian、UTF-8共6種編碼之間的任意轉換。

2.問題解決                                                                                                                                                                                         

(1)編碼基礎知識

a.了解編碼和字元集

這部分内容,我不在贅述,可參見CSDN Ancky的專欄中《各種字元集和編碼詳解》

部落格位址:http://blog.csdn.net/ancky/article/details/2034809

b.單位元組、雙位元組、多位元組

這部分内容,可參見我先前翻譯的博文《C++字元串完全指南--第一部分:win32 字元編碼》

部落格位址:http://blog.csdn.net/ziyuanxiazai123/article/details/7482360

c.區域和代碼頁

這部分内容,可參見部落格      http://hi.baidu.com/tzpwater/blog/item/bd4abb0b60bff1db3ac7636a.html

d.中文編碼GB2312、GBK、Big5,這部分内容請參見CSDN  lengshine 部落格中《GB2312、GBK、Big5漢字編碼

》,部落格位址:http://blog.csdn.net/lengshine/article/details/5470545

e.Windows程式的字元編碼

這部分内容,可參見部落格http://blog.sina.com.cn/s/blog_4e3197f20100a6z2.html 中《Windows程式的字元編碼》

(2)編碼總結

a.六種編碼的特點

六種編碼的特點如下圖所示:

中文編碼轉換---6種編碼30個方向的轉換

b.編碼存儲差别

ANSI(在簡體中文中預設為GB2312)、Unicode、Unicode big endian 、UTF-8存儲存在差别。

以中文"你好"二字為例,他們存貯格式如下圖所示:

中文編碼轉換---6種編碼30個方向的轉換

c.GB2312、Big5、GBK編碼的差別

三者中漢字均采用二個位元組表示,但是位元組表示的值範圍有所不同,如下圖所示:

中文編碼轉換---6種編碼30個方向的轉換

(3)編碼轉換方式

6種編碼互相轉換,由排列組合知識知道共有30個方向的轉換.筆者采用的轉換方法,

多位元組檔案與Unicode檔案轉換如下圖所示:

中文編碼轉換---6種編碼30個方向的轉換

多位元組檔案之間轉換如下圖所示:

中文編碼轉換---6種編碼30個方向的轉換

(4)編碼轉換使用的三個函數

a.MultiByteToWideChar

該函數完成多位元組字元串向Unicode寬字元串的轉換.

函數原型為:

int MultiByteToWideChar(
  UINT CodePage,         // 代碼頁
  DWORD dwFlags,         // 轉換标志
  LPCSTR lpMultiByteStr, // 待轉換的字元串
  int cbMultiByte,       // 待轉換字元串的位元組數目
  LPWSTR lpWideCharStr,  // 轉換後寬字元串的存儲空間
  int cchWideChar        // 轉換後寬字元串的存儲空間大小  以寬字元大小為機關
);
b.WideCharToMultiByte
該函數完成Unicode寬字元串到多位元組字元串的轉換,使用方法具體參見MSDN。
以上兩個函數可以完成大部分的字元串轉換,可以将其封裝成多位元組和寬位元組之間的轉換函數:

       
wchar_t* Coder::MByteToWChar(UINT CodePage,LPCSTR lpcszSrcStr)
{
	LPWSTR lpcwsStrDes=NULL;
	int   len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,NULL,0);
    lpcwsStrDes=new wchar_t[len+1];
	if(!lpcwsStrDes)
		return NULL;
	memset(lpcwsStrDes,0,sizeof(wchar_t)*(len+1));
    len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,lpcwsStrDes,len);
	if(len)
		return lpcwsStrDes;
	else
	{   
		delete[] lpcwsStrDes;
		return NULL;
	}
}

char* Coder::WCharToMByte(UINT CodePage,LPCWSTR lpcwszSrcStr)
{
	char* lpszDesStr=NULL;
	int len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,NULL,0,NULL,NULL);
	lpszDesStr=new char[len+1];
	memset(lpszDesStr,0,sizeof(char)*(len+1));
	if(!lpszDesStr)
		return NULL;
	len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,lpszDesStr,len,NULL,NULL);
	if(len)
		return lpszDesStr;
	else
	{   
		delete[] lpszDesStr;
		return NULL;
	}
} 
           
c.LCMapString 依賴于本地機器的字元轉換函數,尤其是中文編碼在轉換時要依賴于本地機器, 直接利用上述a、b中叙述的函數會産生錯誤,例如直接從GB2312轉換到Big5,利用
MultiByteToWideChar函數将GB2312轉換到Unicode字元串,然後從Unicode字元串利用函數       
WideCharToMultiByte轉換成Big5,将會發生錯誤,錯誤的結果如下圖所示:

        
中文編碼轉換---6種編碼30個方向的轉換
是以中文編碼轉換時适當使用LCMapString函數,才能完成正确的轉換. 例如:
//簡體中文 GB2312 轉換成 繁體中文BIG5
char* Coder::GB2312ToBIG5(const char* szGB2312Str)
{       
        LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
        int nLength = LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,NULL,0);
        char* pBuffer=new char[nLength+1];
		if(!pBuffer)
			return NULL;
        LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,pBuffer,nLength);
        pBuffer[nLength]=0;
        wchar_t* pUnicodeBuff = MByteToWChar(CP_GB2312,pBuffer);
        char* pBIG5Buff = WCharToMByte(CP_BIG5,pUnicodeBuff);
        delete[] pBuffer;
        delete[] pUnicodeBuff;
        return pBIG5Buff;
} 
           
(5)編碼實作 實作Coder類完成編碼轉換工作. Coder類的代碼清單如下:
// Coder.h: interface for the Coder class.
//
//

#if !defined(AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_)
#define AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//-----------------------------------------------------------------------------------------------
//程式用途:實作GB2312、big5、GBK、Unicode、Unicode big endian、UTF-8六種編碼的任意裝換    
//程式作者:湖北師範學院計算機科學與技術學院  王定橋                                 
//核心算法:根據不同編碼特點向其他編碼轉換
//測試結果:在Windows7 VC6.0環境下測試通過      	  					          				  
//制作時間:2012-04-24											  
//代碼版權:代碼公開供學習交流使用  歡迎指正錯誤  改善算法
//-----------------------------------------------------------------------------------------------
//Windows代碼頁
typedef enum CodeType
{
    CP_GB2312=936,
    CP_BIG5=950,
	CP_GBK=0         //此處特殊處理 CP_GBK僅作一标志  GBK代碼頁值尚未查得 
}CodePages;
//txt檔案編碼
typedef enum TextCodeType
{   
	GB2312=0,
	BIG5=1,
	GBK=2,
	UTF8=3,
	UNICODE=4,
	UNICODEBIGENDIAN=5,
	DefaultCodeType=-1
}TextCode;
class Coder  
{
public:
	Coder();
	virtual ~Coder();
public:
	//預設一次轉換位元組大小
	UINT  PREDEFINEDSIZE;
	//指定轉換時預設一次轉換位元組大小
	void SetDefaultConvertSize(UINT nCount);
	//編碼類型轉換為字元串
	CString  CodeTypeToString(TextCode tc);
	//檔案轉到另一種檔案
	BOOL     FileToOtherFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode  tcCur=DefaultCodeType);
	//Unicode 和Unicode big endian檔案之間轉換
	BOOL     UnicodeEndianFileConvert(CString filesourcepath, CString filesavepath,TextCode tcTo);
	//多位元組檔案之間的轉換
	BOOL     MBFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode  tcCur=DefaultCodeType);
	//Unicode和Unicode big endian檔案向多位元組檔案轉換
	BOOL     UnicodeFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo);
	//多位元組檔案向Unicode和Unicode big endian檔案轉換
	BOOL     MBFileToUnicodeFile(CString filesourcepath,CString filesavepath,TextCode tcTo,TextCode  tcCur=DefaultCodeType);
	//擷取檔案編碼類型
	TextCode GetCodeType(CString filepath);
	//繁體中文BIG5 轉換成 簡體中文 GB2312
	char* BIG5ToGB2312(const char* szBIG5Str);
	//簡體中文 GB2312 轉換成 繁體中文BIG5
    char* GB2312ToBIG5(const char* szGB2312Str);
	//簡繁中文GBK編碼轉換成簡體中文GB2312
	char* GBKToGB2312(const char *szGBkStr);
	//簡體中文GB2312編碼轉換成簡繁中文GBK
	char*    GB2312ToGBK(const char *szGB2312Str);
	//簡繁中文GBK轉換成繁體中文Big5
	char*     GBKToBIG5(const char *szGBKStr);
	//繁體中文BIG5轉換到簡繁中文GBK
	char*     BIG5ToGBK(const char *szBIG5Str);
	//寬字元串向多位元組字元串轉換
	char*     WCharToMByte(UINT CodePage,LPCWSTR lpcwszSrcStr);
	//多位元組字元串向寬字元串轉換
	wchar_t*  MByteToWChar(UINT CodePage,LPCSTR lpcszSrcStr);
protected:
	//擷取編碼類型對應的代碼頁
	UINT GetCodePage(TextCode tccur);
	//多位元組向多位元組轉換
	char*  MByteToMByte(UINT CodePageCur,UINT CodePageTo,const char* szSrcStr);
	//Unicode和Unicode big endian字元串之間的轉換
	void   UnicodeEndianConvert(LPWSTR  lpwszstr);
	//檔案頭常量位元組數組
	const  static   byte UNICODEBOM[2];
	const  static   byte UNICODEBEBOM[2];
	const  static   byte UTF8BOM[3];
  };

#endif // !defined(AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_)
           
// Coder.cpp: implementation of the Coder class.
//
//

#include "stdafx.h"
#include "Coder.h"
#include "Encoding.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//
//初始化檔案頭常量
/*static*/ const     byte Coder::UNICODEBOM[2]={0xFF,0xFE};
/*static*/ const     byte Coder::UNICODEBEBOM[2]={0xFE,0xFF};
/*static*/ const     byte Coder::UTF8BOM[3]={0xEF,0xBB,0xBF};
Coder::Coder()
{
   PREDEFINEDSIZE=2097152;//預設一次轉換位元組大小 2M位元組
}
Coder::~Coder()
{
  
}
//繁體中文BIG5 轉換成 簡體中文 GB2312
char* Coder::BIG5ToGB2312(const char* szBIG5Str)
{       
		CString msg;
        LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
        wchar_t* szUnicodeBuff =MByteToWChar(CP_BIG5,szBIG5Str);
        char* szGB2312Buff =WCharToMByte(CP_GB2312,szUnicodeBuff);
        int nLength = LCMapString(lcid,LCMAP_SIMPLIFIED_CHINESE, szGB2312Buff,-1,NULL,0);
        char* pBuffer = new char[nLength + 1];
		if(!pBuffer)
          return NULL;
		memset(pBuffer,0,sizeof(char)*(nLength+1));
        LCMapString(0x0804,LCMAP_SIMPLIFIED_CHINESE,szGB2312Buff,-1,pBuffer,nLength);
        delete[] szUnicodeBuff;
        delete[] szGB2312Buff;
        return pBuffer;
}
// GB2312 轉 GBK
char* Coder::GB2312ToGBK(const char *szGB2312Str)
{
	   int nStrLen = strlen(szGB2312Str);
	   if(!nStrLen)
		   return NULL;
	   LCID wLCID = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_PRC);
	   int nReturn = LCMapString(wLCID, LCMAP_TRADITIONAL_CHINESE, szGB2312Str, nStrLen, NULL, 0);
	   if(!nReturn)
		  return NULL;
	   char *pcBuf = new char[nReturn + 1];
	   if(!pcBuf)
          return NULL;
	   memset(pcBuf,0,sizeof(char)*(nReturn + 1));
	   wLCID = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_PRC);
	   LCMapString(wLCID, LCMAP_TRADITIONAL_CHINESE, szGB2312Str, nReturn, pcBuf, nReturn);
	   return pcBuf;
}
// GBK 轉換成 GB2312
char* Coder::GBKToGB2312(const char *szGBKStr)
{
	int nStrLen = strlen(szGBKStr);
	if(!nStrLen)
		return NULL;
	LCID wLCID = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_BIG5);
	int nReturn = LCMapString(wLCID, LCMAP_SIMPLIFIED_CHINESE, szGBKStr, nStrLen, NULL, 0);
	if(!nReturn)
		return NULL;
	char *pcBuf = new char[nReturn + 1];
	memset(pcBuf,0,sizeof(char)*(nReturn + 1));
	wLCID = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_BIG5);
	LCMapString(wLCID, LCMAP_SIMPLIFIED_CHINESE, szGBKStr, nReturn, pcBuf, nReturn);
	return pcBuf;
}
//簡繁中文GBK轉換成繁體中文Big5
char*   Coder::GBKToBIG5(const char *szGBKStr)
{   
	char *pTemp=NULL;
	char *pBuffer=NULL;
	pTemp=GBKToGB2312(szGBKStr);
	pBuffer=GB2312ToBIG5(pTemp);
	delete[] pTemp;
	return pBuffer;
}
//繁體中文BIG5轉換到簡繁中文GBK
char*   Coder::BIG5ToGBK(const char *szBIG5Str)
{
	  char *pTemp=NULL;
	  char *pBuffer=NULL;
	  pTemp=BIG5ToGB2312(szBIG5Str);
	  pBuffer=GB2312ToGBK(pTemp);
	  delete[] pTemp;
	  return pBuffer;
}
//簡體中文 GB2312 轉換成 繁體中文BIG5
char* Coder::GB2312ToBIG5(const char* szGB2312Str)
{       
        LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
        int nLength = LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,NULL,0);
        char* pBuffer=new char[nLength+1];
		if(!pBuffer)
			return NULL;
        LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,pBuffer,nLength);
        pBuffer[nLength]=0;
        wchar_t* pUnicodeBuff = MByteToWChar(CP_GB2312,pBuffer);
        char* pBIG5Buff = WCharToMByte(CP_BIG5,pUnicodeBuff);
        delete[] pBuffer;
        delete[] pUnicodeBuff;
        return pBIG5Buff;
} 
//擷取檔案編碼類型
//Unicode編碼檔案通過讀取檔案頭判别
//中文編碼通過統計檔案編碼類别來判别  判别次數最多為30次  
//中文編碼的判别存在誤差
TextCode Coder::GetCodeType(CString filepath)
{
    CFile file;
	byte  buf[3];//unsigned char
	TextCode tctemp;
	if(file.Open(filepath,CFile::modeRead))
	{    
		file.Read(buf,3);
		if(buf[0]==UTF8BOM[0] && buf[1]==UTF8BOM[1] && buf[2]==UTF8BOM[2])
			return UTF8;
		else
		if(buf[0]==UNICODEBOM[0] &&buf[1]==UNICODEBOM[1] )
			return UNICODE ;
		else
		if(buf[0]==UNICODEBEBOM[0] &&buf[1]==UNICODEBEBOM[1] )
			return UNICODEBIGENDIAN;
        else
		{   
			int time=30;
			while(file.Read(buf,2) &&time )
			{   
				if ( (buf[0]>=176 && buf[0]<=247) && (buf[1]>=160 && buf[1]<=254) )
							tctemp=GB2312;	
				else
					if ( (buf[0]>=129 && buf[0]<=255) && (  ( buf[1]>=64 && buf[1]<=126)  ||  ( buf[1]>=161 && buf[1]<=254) ) )
							tctemp=BIG5;
					else
						if ( (buf[0]>=129 && buf[0] <=254) && (buf[1]>=64 && buf[1]<=254))
							tctemp=GBK;	
				time--;
				file.Seek(100,CFile::current);//跳過一定位元組  利于統計全文
			}
			return tctemp;
		}
	}
	else
		return GB2312;
}
//多位元組檔案轉換為UNICODE、UNICODE big endian檔案
BOOL Coder::MBFileToUnicodeFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode tcCur)
{
   TextCode curtc;
   CFile filesource,filesave;;
   char     *pChSrc=NULL;
   char     *pChTemp=NULL;
   wchar_t  *pwChDes=NULL;
   DWORD  filelength,readlen,len;
   int    bufferlen,strlength;
   UINT CodePage;
   //由于存在誤差  允許使用者自定義轉換
   if(tcCur!=DefaultCodeType)
	   curtc=tcCur;
   else
	   curtc=GetCodeType(filesourcepath);
   if(curtc>UTF8 || tcTo< UNICODE || curtc==tcTo)
	   return FALSE;
   //源檔案打開失敗或者源檔案無内容 後者儲存檔案建立失敗   均傳回轉換失敗
   if(!filesource.Open(filesourcepath,CFile::modeRead) || 0==(filelength=filesource.GetLength()))
	   return FALSE;
   if( !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
		return FALSE;
   //預配置設定記憶體  配置設定失敗則轉換失敗
   if(filelength<PREDEFINEDSIZE)
	   bufferlen=filelength;
   else
	   bufferlen=PREDEFINEDSIZE;
   pChSrc=new char[bufferlen+1];
   if(!pChSrc)
			return FALSE;
   //根據目前檔案類别指定轉換代碼頁
   switch(curtc)
   {
   case GB2312:
	   CodePage=CP_GB2312;
	   break;
   case GBK:
	   CodePage=CP_GB2312;//特殊處理
	   break;
   case BIG5:
	   CodePage=CP_BIG5;
	   break;
   case UTF8:
	   CodePage=CP_UTF8;
	   break;
   default:
	   break;
	}
   //UTF8檔案跳過檔案
   if(UTF8==curtc)
	   filesource.Seek(3*sizeof(byte),CFile::begin);
   //寫入檔案頭
   if(UNICODEBIGENDIAN==tcTo)
	   filesave.Write(&UNICODEBEBOM,2*sizeof(byte));
   else
       filesave.Write(&UNICODEBOM,2*sizeof(byte));
   //讀取檔案  分段轉換知道結束
   while(filelength>0)
   {
	   memset(pChSrc,0, sizeof(char)*(bufferlen+1));
	   if(filelength>PREDEFINEDSIZE)
		   len=PREDEFINEDSIZE;
	   else
		   len=filelength;
	   readlen=filesource.Read(pChSrc,len);
	   if(!readlen)
			break;
	   //GBK轉換為GB2312處理
	   if(GBK==curtc)
	   {   
		   pChTemp=pChSrc;
		   pChSrc=GBKToGB2312(pChSrc);
	   }
	   pwChDes=MByteToWChar(CodePage,pChSrc);
	   if(pwChDes)
	   {
		   if(UNICODEBIGENDIAN==tcTo)
			   UnicodeEndianConvert(pwChDes);
		   strlength=wcslen(pwChDes)*2;//這裡注意寫入檔案的長度
		   filesave.Write(pwChDes,strlength);
		   filesave.Flush();
		   filelength-=readlen;
	   }
	   else
		   break;
   }
   delete[] pChSrc;
   delete[] pChTemp;
   delete[] pwChDes;
   return TRUE;
}
//
wchar_t* Coder::MByteToWChar(UINT CodePage,LPCSTR lpcszSrcStr)
{
	LPWSTR lpcwsStrDes=NULL;
	int   len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,NULL,0);
    lpcwsStrDes=new wchar_t[len+1];
	if(!lpcwsStrDes)
		return NULL;
	memset(lpcwsStrDes,0,sizeof(wchar_t)*(len+1));
    len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,lpcwsStrDes,len);
	if(len)
		return lpcwsStrDes;
	else
	{   
		delete[] lpcwsStrDes;
		return NULL;
	}
}

char* Coder::WCharToMByte(UINT CodePage,LPCWSTR lpcwszSrcStr)
{
	char* lpszDesStr=NULL;
	int len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,NULL,0,NULL,NULL);
	lpszDesStr=new char[len+1];
	memset(lpszDesStr,0,sizeof(char)*(len+1));
	if(!lpszDesStr)
		return NULL;
	len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,lpszDesStr,len,NULL,NULL);
	if(len)
		return lpszDesStr;
	else
	{   
		delete[] lpszDesStr;
		return NULL;
	}
} 
//Unicode 和Unicode big endian之間位元組序的轉換
void Coder::UnicodeEndianConvert(LPWSTR lpwszstr)
{    
	 wchar_t  wchtemp[2];  
	 long     index; 
	 int len=wcslen(lpwszstr);
     if(!len)
		 return;
   //交換高低位元組 直到遇到結束符
   index=0;
   while( index<len)
   {
       wchtemp[0]=lpwszstr[index];
       wchtemp[1]=lpwszstr[index+1];
	   
	   unsigned char high, low;
	   high = (wchtemp[0] & 0xFF00) >>8;
	   low  = wchtemp[0] & 0x00FF;
	   wchtemp[0] = ( low <<8) | high;
	   high = (wchtemp[1] & 0xFF00) >>8;
	   low  = wchtemp[1] & 0x00FF;
	   wchtemp[1] = ( low <<8) | high;
       
	   lpwszstr[index]=wchtemp[0];
	   lpwszstr[index+1]=wchtemp[1];
	   index+=2;
   }
}
//Unicode和Unicode big endian檔案向多位元組檔案轉換
BOOL Coder::UnicodeFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo)
{   
	TextCode curtc;
	CFile filesource,filesave;;
	char    *pChDes=NULL;
	char    *pChTemp=NULL;
	wchar_t *pwChSrc=NULL;
	DWORD  filelength,readlen,len;
	int    bufferlen,strlength;
	UINT CodePage;
	curtc=GetCodeType(filesourcepath);
	//檔案轉換類型錯誤 則轉換失敗
	if(curtc<=UTF8 ||  tcTo>UTF8 || curtc==tcTo)
		return FALSE;
    //源檔案打開失敗或者源檔案無内容 後者儲存檔案建立失敗   均轉換失敗
    if(!filesource.Open(filesourcepath,CFile::modeRead) || 0==(filelength=filesource.GetLength()))
		return FALSE;
	if( !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
		return FALSE;
	//預配置設定記憶體  配置設定失敗則轉換失敗
	if(filelength<PREDEFINEDSIZE)
		bufferlen=filelength;
	else
		bufferlen=PREDEFINEDSIZE;
	pwChSrc=new wchar_t[(bufferlen/2)+1];
	if(!pwChSrc)
		return FALSE;
	//預先決定代碼頁
	switch(tcTo)
	{   
	case GB2312:
		CodePage=CP_GB2312;
		break;
	case GBK:
		CodePage=CP_GB2312;//特殊處理
		break;
	case BIG5: 
		CodePage=CP_GB2312;//特殊處理
		break;
	case UTF8:
		CodePage=CP_UTF8;
		break;
	default:
		break;
		}
	filesource.Seek(sizeof(wchar_t),CFile::begin);
	while(filelength>0)
	{
		memset(pwChSrc,0,sizeof(wchar_t)*((bufferlen/2)+1));
		if(filelength>PREDEFINEDSIZE)
			len=PREDEFINEDSIZE;
		else
			len=filelength;
		readlen=filesource.Read(pwChSrc,len);
		if(!readlen)
			break;
		if(UNICODEBIGENDIAN==curtc)
			UnicodeEndianConvert(pwChSrc);
		pChDes=WCharToMByte(CodePage,pwChSrc);
		//GBK無法直接轉換  BIG5直接轉換會産生錯誤  二者均先轉到GB2312然後再轉到目的類型
		if(GBK==tcTo)
		{
			pChTemp=pChDes;
			pChDes=GB2312ToGBK(pChDes);
		}
		if(BIG5==tcTo)
		{
			pChTemp=pChDes;
			pChDes=GB2312ToBIG5(pChDes);
		}
		if(pChDes)
		{   
			strlength=strlen(pChDes);
			filesave.Write(pChDes,strlength);
			filesave.Flush();
			filelength-=readlen;
		}
		else
			break;
	}
    delete[] pChDes;
	delete[] pChTemp;
	delete[] pwChSrc;
	return TRUE;
}
//多位元組檔案轉為多位元組檔案
//多位元組轉為多位元組時,一般先轉為UNICODE類型,再轉換到指定目的類型,實行兩次轉換
BOOL Coder::MBFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode  tcCur)
{
	BOOL bret=FALSE;
	TextCode curtc;
	CFile filesource,filesave;
	char    *pChDes=NULL;
	char    *pChSrc=NULL;
	DWORD  filelength,readlen,len;
	int    bufferlen,strlength;
	UINT   CodePageCur,CodePageTo;
	//由于存在誤差  允許使用者自定義轉換
	if(DefaultCodeType!=tcCur)
         curtc=tcCur;
	else
		curtc=GetCodeType(filesourcepath);
	//轉換類型錯誤  則傳回轉換失敗
	if(curtc>UTF8 || tcTo>UTF8 || curtc==tcTo)
		return FALSE;
	//源檔案打開失敗或者源檔案無内容 後者儲存檔案建立失敗   均傳回轉換失敗
    if(!filesource.Open(filesourcepath,CFile::modeRead) || 0==(filelength=filesource.GetLength()))
		return FALSE;
	if( !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
		return FALSE;
	//預配置設定記憶體  配置設定失敗則轉換失敗
	if(filelength<PREDEFINEDSIZE)
		bufferlen=filelength;
	else
		bufferlen=PREDEFINEDSIZE;
    pChSrc=new char[bufferlen+1];
	if(!pChSrc)
			return FALSE;
	if(UTF8==curtc)
		filesource.Seek(3*sizeof(byte),CFile::begin);
	CodePageCur=GetCodePage(curtc);
    CodePageTo=GetCodePage(tcTo);
	while(filelength>0)
	{   
		memset(pChSrc,0,sizeof(char)*(bufferlen+1));
        if(filelength>PREDEFINEDSIZE)
			len=PREDEFINEDSIZE;
		else
			len=filelength;
		readlen=filesource.Read(pChSrc,len);
		if(!readlen)
			break;
		pChDes=MByteToMByte(CodePageCur,CodePageTo,pChSrc);
		if(pChDes)
		{   
			strlength=strlen(pChDes);
			filesave.Write(pChDes,strlength);
			filelength-=readlen;
		}
		else
			break;
	}
	delete[] pChSrc;
	delete[] pChDes;
	return TRUE;
}
//Unicode 和Unicode big endian檔案之間轉換
BOOL Coder::UnicodeEndianFileConvert(CString filesourcepath, CString filesavepath,TextCode tcTo)
{
	TextCode curtc=GetCodeType(filesourcepath);
	if(curtc!=UNICODE && curtc!=UNICODEBIGENDIAN)
		return FALSE;
	if(curtc==tcTo)
		return FALSE;
	CFile filesource,filesave;;
	wchar_t *pwChDes;
	DWORD length;
    if(!filesource.Open(filesourcepath,CFile::modeRead) || !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
		return FALSE;
	length=filesource.GetLength();
	if(!length)
		return FALSE;
	pwChDes=new wchar_t[(length/2)+1];
	if(!pwChDes)
		return FALSE;
	memset(pwChDes,0,sizeof(wchar_t)*((length/2)+1));
	filesource.Read(pwChDes,length);
	UnicodeEndianConvert(pwChDes);
	length=wcslen(pwChDes)*2;
	if(UNICODE==tcTo)
        filesave.Write(&UNICODEBOM,2*sizeof(byte));
	else
		filesave.Write(&UNICODEBEBOM,2*sizeof(byte));
	filesave.Write(pwChDes,length);
	filesave.Flush();
	delete[] pwChDes;
	return TRUE;
}
//檔案轉到另一種檔案
//6種格式檔案兩兩轉換  共計30種轉換
BOOL Coder::FileToOtherFile(CString filesourcepath, CString filesavepath, TextCode tcTo,TextCode  tcCur)
{   
	TextCode curtc;
	BOOL bret=FALSE;
	if(DefaultCodeType!=tcCur)
        curtc=tcCur;
	else
	    curtc=GetCodeType(filesourcepath);
	if(curtc==tcTo)
		return FALSE;
	//UNICODE和UNICODE big endian檔案之間轉換 共2種
	if(curtc>=UNICODE&& tcTo>=UNICODE)
			bret=UnicodeEndianFileConvert(filesourcepath,filesavepath,tcTo);
	else
		//多位元組檔案向 UNICODE和UNICODE big endian檔案之間轉換 共8種
		if(curtc<UNICODE && tcTo>=UNICODE)
			bret=MBFileToUnicodeFile(filesourcepath,filesavepath,tcTo,curtc);
	else
		//UNICODE和UNICODE big endian檔案向多位元組檔案轉換 共8種
		if(curtc>=UNICODE && tcTo<UNICODE)
			bret=UnicodeFileToMBFile(filesourcepath,filesavepath,tcTo);
	else
		//多位元組檔案之間轉換 共12種
		if(curtc<UNICODE && tcTo<UNICODE)
			bret=MBFileToMBFile(filesourcepath,filesavepath,tcTo,curtc);
	return bret;
}
//編碼類型轉換為字元串
CString Coder::CodeTypeToString(TextCode tc)
{
      CString strtype;
	  switch(tc)
	  {
	  case GB2312:
           strtype=_T("GB2312");
		   break;
	  case BIG5:
		  strtype=_T("Big5");
		   break;
	  case GBK:
		  strtype=_T("GBK");
		   break;
	  case UTF8:
		  strtype=_T("UTF-8");
		   break;
	  case UNICODE:
		  strtype=_T("Unicode");
		   break;
	  case UNICODEBIGENDIAN:
		  strtype=_T("Unicode big endian");
		   break;
	  }
	  return strtype;
}
//多位元組向多位元組轉換
char* Coder::MByteToMByte(UINT CodePageCur, UINT CodePageTo, const char* szSrcStr)
{
	char    *pchDes=NULL;
	char    *pchTemp=NULL;
	wchar_t *pwchtemp=NULL;
	//三種中文編碼之間轉換
	if(CodePageCur!=CP_UTF8  && CodePageTo!=CP_UTF8)
	{
		switch(CodePageCur)
		{
			case CP_GB2312:
				{
					if(CP_BIG5==CodePageTo)	
                       pchDes=GB2312ToBIG5(szSrcStr);
					else
                       pchDes=GB2312ToGBK(szSrcStr);
					break;
				}
			case CP_BIG5:
				{   
					if(CP_GB2312==CodePageTo)
						pchDes=BIG5ToGB2312(szSrcStr);
					else
						pchDes=BIG5ToGBK(szSrcStr);
                    break;
				}
			case CP_GBK:
				{   
					if(CP_GB2312==CodePageTo)
						pchDes=GBKToGB2312(szSrcStr);
					else
						pchDes=GBKToBIG5(szSrcStr);
                    break;
				}
		}
	}
	else
	{    //從UTF-8轉到其他多位元組  直接轉到GB2312 其他形式用GB2312做中間形式
         if(CP_UTF8==CodePageCur)
		 {  
			pwchtemp=MByteToWChar(CodePageCur,szSrcStr);
			if(CP_GB2312==CodePageTo)
			{
				pchDes=WCharToMByte(CP_GB2312,pwchtemp);
			}
			else
			{    
				pchTemp=WCharToMByte(CP_GB2312,pwchtemp);
			     if(CP_GBK==CodePageTo)
					pchDes=GB2312ToGBK(pchTemp);
				 else
					pchDes=GB2312ToBIG5(pchTemp);
			}
		 }
		 //從其他多位元組轉到UTF-8
		 else 
		 {    
			  if(CP_GBK==CodePageCur)
			  {   

				  pchTemp=GBKToGB2312(szSrcStr);
                  pwchtemp=MByteToWChar(CP_GB2312,pchTemp);
			  }
			  else
				pwchtemp=MByteToWChar(CodePageCur,szSrcStr);
              pchDes=WCharToMByte(CodePageTo,pwchtemp);
		 }
	}
    delete[] pchTemp;
	delete[] pwchtemp;
	return pchDes;
}
//擷取編碼類型對應的代碼頁
UINT Coder::GetCodePage(TextCode tccur)
{
      UINT CodePage;
	  switch(tccur)
	  {
	  case GB2312:
		  CodePage=CP_GB2312;
		  break;
	  case BIG5:
		  CodePage=CP_BIG5;
		  break;
	  case GBK:
		  CodePage=CP_GBK;
		  break;
	  case UTF8:
		  CodePage=CP_UTF8;
		  break;
	  case UNICODEBIGENDIAN:
	  case UNICODE:
		   break;
	}
	  return CodePage;
}
//指定轉換時預設一次轉換位元組大小
void Coder::SetDefaultConvertSize(UINT nCount)
{    
	 if(nCount!=0)
		PREDEFINEDSIZE=nCount;
}
           
3.運作效果 在win7 VC 6.0下測試六種編碼的轉換測試通過,30個方向的轉換如下圖所示:
中文編碼轉換---6種編碼30個方向的轉換
測試程式運作效果如下圖所示:
中文編碼轉換---6種編碼30個方向的轉換
GB2312轉換到GBK編碼效果如下圖所示:
中文編碼轉換---6種編碼30個方向的轉換

UTF-8轉換到Big5編碼的效果如下圖所示:

中文編碼轉換---6種編碼30個方向的轉換

本文代碼及轉碼程式下載下傳 :http://download.csdn.net/user/ziyuanxiazai123

4.尚未解決的問題                                                                                                                                                                             

(1)LCMapString函數的了解還不完全熟悉,其中參數偏多,了解需要一定基礎知識。

(2)為什麼記事本程式的轉碼後存在些亂碼,亂碼是正确的嗎?因為我的程式使用了中間過渡形式,是以沒有任何亂碼。

(3)是否有更簡單和清晰的方式實作編碼轉換,待進一步研究。