涉及多平台版本的中英文字符文件读写和转换

89 篇文章 5 订阅


参考文档:

http://msdn.microsoft.com/en-us/library/aa300688(v=vs.60).aspx

http://msdn.microsoft.com/zh-cn/library/5z097dxa(v=vs.90).aspx

http://msdn.microsoft.com/zh-cn/library/87zae4a3(v=vs.90).aspx

http://blog.csdn.net/masefee/article/details/6835688

http://blog.csdn.net/chunyexiyu/article/details/8938540

http://blog.csdn.net/chunyexiyu/article/details/9001158

Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu  转载请标明来源 

 

 

1. 在多个编译版本中,中英文在传递时,可能采用不同的格式 

_UNICODE定义时,中英文字符都按unicode格式存储(CString使用CStringW-wchar_t型存储)

MBCS时,英文字符1个字节,中文字符两个字节(CString使用CStringA-char型存储)

 

参考下面来自msdn的说明:我们看到CString基于_UNICODE宏,存储数据char 或 w_char类型。

CString is based on the TCHAR data type. If the symbol _UNICODE is defined for your program, TCHAR is defined as type wchar_t, a 16-bit character type; otherwise, it is defined as char, the normal 8-bit character type. Under Unicode, then, CString objects are composed of 16-bit characters. Without Unicode, they are composed of 8-bit char type.

When not using _UNICODE, CString is enabled for multibyte character sets (MBCS, also known as double-byte character sets, DBCS). 


再来看下:MBCS说明

最常见的 MBCS 实现是双字节字符集 (DBCS)。一般来说,Visual C++(尤其是 MFC)完全支持 DBCS
在 MBCS 下,字符被编码为单字节或双字节。在双字节字符中,第一个字节(即前导字节)表示它和下一个字节将被解释为一个字符。第一个字节来自留作前导字节的代码范围。哪个范围的字节可以用作前导字节取决于所使用的代码页。例如,日文代码页 932 使用 0x81 到 0x9F 范围内的字节作为前导字节,而朝鲜语代码页 949 则使用其他范围的字节。


 

2. 当我们涉及中英文存储交互的时候,需要同时支持两种情况(MBCS/UNICODE)

程序怎么写? 

 配置文件怎么写?

关于我个人当前有这两种思路

第一种:文件格式固定

例如:文件格式我们采用uncode存储;

读取时:程序本身在运行的时候,判断当前是unicode,还是mbcs,采用

sizeof(TCHAR) == 1 则为 mbcs

sizeof(TCHAR) == 2 则为 unicode

当为unicode时,则直接从文件中读取字符串即可,就能读到正确的中英文字符,这些读出的内容可以正确展现到界面中去

当程序以mbcs格式运行时,需要把unicode的字符串内容,通过转换,转换成mbcs,然后再展现到界面中去

写入时:我们一定要采用unicode写入,当系统为mbcs时,我们把数据转为unicode存储到wchar_t*的buffer中,然后写入。

 

第二种:记录字符串格式到文件中

例如:程序写入文件的时候,判断当前的环境,如果为mbcs,则记录1,如果为unicode,则记录0。

在读取的时候,先判断自身的运行环境mbcs/unicode,然后再读入文件中的信息mbcs/unicode;如果两者一致,则直接读入即可。

如果两者不一致,则需要转换,转换到对应的运行环境中的格式。

例如:环境为unicode,文件存储的是mbcs,则需要把文件中的字符串转为unicode,然后再展示

            环境为mbcs,文件存储为unicode,则需要把文件中的字符床转为mbcs,然后展示到界面中

 

 

3. MBCS/UNICODE转换的方法

我们可以采用如http://blog.csdn.net/chunyexiyu/article/details/8938540中的方法转换(MultiByteToWideChar,WideCharToMultiByte)

这里介绍一个MFC中常用的方法

Unicode to  ANSI:假如文件存储的类型是Unicode,环境的类型是MBCS

CString cstrName; // 环境为Unicode时,CString等同于CStringA,存储的数据为char类型
BYTE *pBuffer = new BYTE[dwStrNameLength];
binFile.Read(pBuffer, dwStrNameLength); // 从文件中读取出Unicode格式来名称
{    
	USER_CONVERSION;    
	cstrName = W2CT(LPCWSTR(pBuffer));
} 
delete pBuffer;

 

 ANSI to  Unicode:假如文件存储的类型是ASNI,环境的类型是Unicode 

CString cstrName; // 环境为Unicode时,CString等同于CStringW,存储的数据为wchar_t类型
BYTE *pBuffer = new BYTE[dwStrNameLength];
binFile.Read(pBuffer, dwStrNameLength);   // 从文件中读取出来ANSI格式存储名称
{    
	USER_CONVERSION;    
	cstrName = A2CT(LPCSTR(pBuffer));
} 
delete pBuffer;

 

 

W2CT,A2CT 参见MSDN中说明:

CSourceType2[C]DestinationType[EX]

where:

  • SourceType and DestinationType are described in the table below.

  • [C] is present when the destination type must be constant.

  • [EX] is present when the initial size of the buffer must be specified as a template argument.

    SourceType/DestinationType

    Description

    A

    ANSI character string.

    W

    Unicode character string.

    T

    Generic character string (equivalent to W when _UNICODE is defined, equivalent to A otherwise).

    OLE

    OLE character string (equivalent to W).

 

4. USER_CONVERSION/W2CT等使用注意事项

USES_CONVERSION的宏定义参考如下:

		int _convert = 0; (_convert); 
		UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); 
		LPCWSTR _lpw = NULL; (_lpw);
		LPCSTR _lpa = NULL; (_lpa)

 

A2W宏定义形如:

	(_lpa = lpa) == NULL) ? NULL : _convert = (lstrlenA(_lpa)+1);
	(INT_MAX/2<_convert)? NULL : ATLA2WHELPER((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, _acp);

W2A宏定义形如:

         ((_lpw = lpw) == NULL) ? NULL : (_convert = (lstrlenW(_lpw)+1), 
	(_convert>INT_MAX/2) ? NULL : ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, _convert*sizeof(WCHAR), _acp)	



其中其内存申请使用的是:alloca

alloca的话从stack申请空间,比较方便,不用我们释放,函数结束,stack地址自然会回退。

不过我们知道stack空间通常是有限制的,例如2M,所以我们使用时,

1. 避免在一个函数中循环使用alloca---担心溢出了

2. 如果确实需要,要么使用别的,例如MultiByteToWideChar; 也或者这样把一次的处理放到函数中,然后循环再调用

    CString InnProc(i) { USER_CONVERSION; ... return A2CT(xxx); }

    void Proc()  {for (...) { xxx = InnProc(i)};

//这样的话,每次执行完InnProc,stack地址就回归一次,就不回越积越多的溢出了

3. alloca出的内存,要返回时,请copy一下再返回,这个和临时变量道理一样. 上面的例子使用的CString把字符串copy了一份拿了出来。要不函数退出时,函数产生的stack数据原则上要清掉的。


关于alloca的详细解释可以参考这篇文档:http://blog.csdn.net/masefee/article/details/6835688

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夜喜雨

稀罕你的喜欢!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值