情況是這樣的,一個程序從ansi移植到了unicode,見
把代碼移植成UNICODE (
http://www.shnenglu.com/flyingxu/archive/2006/05/18/7356.html),之后產生了一個問題,之前文件保存的那些文件,unicode版本還能打開嗎?這真是個大問題,如果不能,就基本表示這個程序已經半死不活了。
文件的保存基本用的序列化,比如
void?CSDITestDoc::Serialize(CArchive&?ar)
{
????if?(ar.IsStoring())
????{
????????//?TODO:?add?storing?code?here
????????ar?<<?m_strName;
????}
????else
????{
????????//?TODO:?add?loading?code?here
????????ar?>>?m_strName;
????}
}
如果m_strName = _T("name");那么ansi情況下,保存的文件為:
04 6E 61 6D 65,一共5個字節。
然后用unicode版本保存時,是
FF FE FF 04 6E 00 61 00 6D 00 65 00,一共12個字節。
然后我發現,ansi版本的可以打開unicode版本的文件,unicode版本的也可以打開ansi版本的文件。
為什么?我覺得關鍵在于CString,我覺得CString功能比較強大。
CString的序列化函數
//?CString?serialization?code
//?String?format:
//??????UNICODE?strings?are?always?prefixed?by?0xff,?0xfffe
//??????if?<?0xff?chars:?len:BYTE,?TCHAR?chars
//??????if?>=?0xff?characters:?0xff,?len:WORD,?TCHAR?chars
//??????if?>=?0xfffe?characters:?0xff,?0xffff,?len:DWORD,?TCHARs
CArchive&?AFXAPI?operator<<(CArchive&?ar,?const?CString&?string)
{
????//?special?signature?to?recognize?unicode?strings
#ifdef?_UNICODE
????ar?<<?(BYTE)0xff;
????ar?<<?(WORD)0xfffe;
#endif
????if?(string.GetData()->nDataLength?<?255)
????{
????????ar?<<?(BYTE)string.GetData()->nDataLength;
????}
????else?if?(string.GetData()->nDataLength?<?0xfffe)
????{
????????ar?<<?(BYTE)0xff;
????????ar?<<?(WORD)string.GetData()->nDataLength;
????}
????else
????{
????????ar?<<?(BYTE)0xff;
????????ar?<<?(WORD)0xffff;
????????ar?<<?(DWORD)string.GetData()->nDataLength;
????}
????ar.Write(string.m_pchData,?string.GetData()->nDataLength*sizeof(TCHAR));
????return?ar;
}
它對unicode做了特別的支持
特別是當它在讀序列化過程的時候
CArchive&?AFXAPI?operator>>(CArchive&?ar,?CString&?string)
{
#ifdef?_UNICODE
????int?nConvert?=?1;???//?if?we?get?ANSI,?convert
#else
????int?nConvert?=?0;???//?if?we?get?UNICODE,?convert
#endif
????UINT?nNewLen?=?_AfxReadStringLength(ar);
????if?(nNewLen?==?(UINT)-1)
????{
????????nConvert?=?1?-?nConvert;
????????nNewLen?=?_AfxReadStringLength(ar);
????????ASSERT(nNewLen?!=?-1);
????}
????//?set?length?of?string?to?new?length
????UINT?nByteLen?=?nNewLen;
#ifdef?_UNICODE
????string.GetBufferSetLength((int)nNewLen);
????nByteLen?+=?nByteLen?*?(1?-?nConvert);??//?bytes?to?read
#else
????nByteLen?+=?nByteLen?*?nConvert;????//?bytes?to?read
????if?(nNewLen?==?0)
????????string.GetBufferSetLength(0);
????else
????????string.GetBufferSetLength((int)nByteLen+nConvert);
#endif
????//?read?in?the?characters
????if?(nNewLen?!=?0)
????{
????????ASSERT(nByteLen?!=?0);
????????//?read?new?data
????????if?(ar.Read(string.m_pchData,?nByteLen)?!=?nByteLen)
????????????AfxThrowArchiveException(CArchiveException::endOfFile);
????????//?convert?the?data?if?as?necessary
????????if?(nConvert?!=?0)
????????{
#ifdef?_UNICODE
????????????CStringData*?pOldData?=?string.GetData();
????????????LPSTR?lpsz?=?(LPSTR)string.m_pchData;
#else
????????????CStringData*?pOldData?=?string.GetData();
????????????LPWSTR?lpsz?=?(LPWSTR)string.m_pchData;
#endif
????????????lpsz[nNewLen]?=?'\0';????//?must?be?NUL?terminated
????????????string.Init();???//?don't?delete?the?old?data
????????????string?=?lpsz;???//?convert?with?operator=(LPWCSTR)
????????????CString::FreeData(pOldData);
????????}
????}
????return?ar;
}
也就是說,不管你保存的文件是不是unicode,都可以讀進來,轉換稱當前unicode或者ansi版本
不過回到文章的標題,這里只講了用CString序列化的保存。如果是其他保存方式,可以學著CString的做法,寫函數把文件總是能讀進來。