
winrar的中文显示不正常, 相对的, 7zip却很出色. 同样的字符集选的是e文. 而选了中文就没问题:

这说明一个问题, winrar的某项字符集转换出错了. 虽然winrar跟7zip都号称支持95/98/me/nt/xp/vista, 可是显然winrar支持的并不好.
我们都知道从windows nt开始的windows api都有2套, 分别对应ansi和unicode, 所以编译的时候如果选了unicode的话, 95/98/me的windows就没法跑了. 但是为了兼容性, 很多程序实际上都是编译成ansi版本的(实际上应该说成是mbcs, multi-byte character set). 那么这个编译选项到底还有什么区别呢?
1) unicode版本在nt以上版本的windows下performance会好一些, 因为os本身就是unicode的.
2) ansi版本可能multi-language做的会比较吃力一些, 这里牵涉到一个codepage的问题, 先来看一下概念, 看几张图:


这两个选项应该都选过的吧, 这就是所谓的codepage(编码页?). 如果你用*nix, 设过locale比如zh_CN.utf-8, zh_CN.gbk的话, 那也就是这个意思. 大多的应用程序会根据这个值来判断, 到底显示什么语言的UI给用户(如果装了windows的MUI包也是这样的). 两张图都是执行cmd的java的输出结果, 可以看到, 一个是e文, 一个就是中文. 那么codepage实际上对之前说的ansi啊unicode啊有什么影响呢? 再来看一张图:

用winhex开了3个文件, 分别是ansi, unicode, utf-8编码. 每个文件里都只有“a”这一个字符.
ansi的话, 直接保存的就是ascii值0x61(暂且这么说, 其实是当前codepage的a的编码).
unicode编码的话多了0xfffe这2个字节, 相对于就是一个标识(这个东西叫BOM, byte-order mark), 告诉你是unicode编码(且是little endian的, big endian的话是0xfeff), 然后再跟一个unicode的a的编码值.
好了, 你突然又看到一个utf-8, 这是个什么东西呢? 这是unicode(废话- -), 不过是这里说的unicode是字符集(character set), 而utf-8, utf-16, 以及之前的little endian的unicode说得都是编码(encoding). 同样的, 0xefbbbf用来标识, 后面再跟a的unicode编码值. 于是你又发现了, 比起unicode编码, utf-8编码似乎简短了些. 没错, unicode编码是定长的, 而utf-8则是变长, 所以网络传输很多时候用的是utf-8, 支持多字节有节省带宽.
背景知识介绍到此, 继续正题.
为什么说ansi版本multi-language会比较麻烦呢? 比如说我在e文的codepage下用notepad打了一个中文的"猪", 保存成ansi的txt, 那么保存的编码实际上是系统当前的编码, 即iso_8859_1. 相对的, 如果是中文的codepage, 那么保存用的则是gbk编码. 所以问题就来了, 你不知道用户到底用的是什么codepage的os啊. 那, 应该怎么解决问题呢?
1) string全部使用一定的编码, 然后通过MultiByteToWideChar(), WideCharToMultiByte()来转换, 这两个函数win95都是支持的.
2) 直接用unicode吧- -...或者打包发布软件的时候mbcs, unicode版本的binary都加. bitcomet, mpc都是采用这用方式的, 如图:

注意: 无论是vs2005的crt还是win32 api, 似乎都不支持直接转换unicode的stream, 所以只能自己写...
bool readFileFromUnicode(char* chFilePath, wchar_t** wchBuffer, int* cchSize)
{
HANDLE hFile = CreateFileA(chFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
DWORD dwSizeHigh = 0, dwSizeLow = 0;
dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
char* chBuffer = new char[dwSizeLow+1];
ZeroMemory(chBuffer, dwSizeLow+1);
DWORD dwRead = 0;
ReadFile(hFile, chBuffer, dwSizeLow, &dwRead, NULL);
CloseHandle(hFile);
bool bSuccess = false;
if (chBuffer[0] == (char)0xff && chBuffer[1] == (char)0xfe)
{
chBuffer += 2;
*wchBuffer = new wchar_t[dwRead/2]; // (dwRead-2)/2+1 = dwRead/2
ZeroMemory(*wchBuffer, (dwRead/2)*sizeof(wchar_t));
for (int i = 0; i < (int)dwRead/2-1; i++)
{
char* pchTemp = (char*)(*wchBuffer+i);
pchTemp[0] = chBuffer[i*2];
pchTemp[1] = chBuffer[i*2+1];
}
*cchSize = dwRead/2-1;
bSuccess = true;
chBuffer -= 2;
}
delete[] chBuffer;
return bSuccess;
}
void readFileFreeBuffer(wchar_t* wchBuffer)
{
delete[] wchBuffer;
}
完整代码点这里.



