[译][boost]Boost.Nowide
翻译源 http://cppcms.com/files/nowide/html/
版权归原作者Artyom Beilis所有
=是什么=
该库提供标准C和C++的库函数的一种实现,这些函数在windows下的输入是UTF-8,而不使用Wide API(Windows函数是区分字符集的:A表示ANSI,W表示Wide,即Unicode)。
=要解决的问题=
考虑一个简单的应用,它将大文件分块,以便将其通过e-mail发送。它需要做简单的几步:
* 访问命令行参数 int main(int argc, char** argv)
* 打开输入文件,打开多个输入文件:std::fstream::open(char const *, std::ios::openmode m)
* 出错时移除文件:std::remove(char const* file)
* 向控制台打印进度:std::cout << file_name
不幸的是,如果文件名称包含非ASCII字符时,只使用原生C++是不可能实现这个简单任务的。
这个使用API的简单程序在那些内部使用UTF-8的系统(大多数的Unix类OS)中能够运行。但在Winsows系统下会在处理某些名称的文件时失败,因为本地Windows Unicode API是Wide-API - UTF16。
这个琐碎的功能在跨平台移植时非常难以处理。
=解决方案=
本库提供一组基于UTF-8的标准库函数,使得Unicode敏感的编程更为容易。
本库提供:
* 易用的UTF-8到UTF-16互相转换的函数
* 一个类,修正argc,argv和环境变量主参数使用UTF-8
* UTF-8敏感函数:
# stdio.h函数
# stdlib.h函数
# fstream
# iostream
=为什么不用Narrow和Wide?=
几个原因:
* wchar_t并不是真正的跨平台,可能是2字节,4字节,甚至是1字节
* 标准C和C++库在OS交互中使用narrow string。本库遵循相同规则。相对于重新以Windows Style实现Wide API,坚持标准方法是更好的选择。
=使用本库=
基本上本库是头文件,只有控制台I/O需要在Windows下单独编译。
作为开发者,我们认为你应当使用boost::nowide函数,而不应当用std名字空间中的函数。
例如,Unicode不敏感的实现:
#include <fstream> #include <iostream> int main(int argc,char **argv) { if(argc!=2) { std::cerr << "Usage: file_name" << std::endl; return 1; } std::ifstream f(argv[1]); if(!f) { std::cerr << "Can't open a file " << argv[1] << std::endl; return 1; } int total_lines = 0; while(f) { if(f.get() == '\n') total_lines++; } f.close(); std::cout << "File " << argv[1] << " has " << total_lines << " lines" << std::endl; return 0; }
处理Unicode时,作如下更改:
#include <boost/nowide/args.hpp> #include <boost/nowide/fstream.hpp> #include <boost/nowide/iostream.hpp> int main(int argc,char **argv) { boost::nowide::args a(argc,argv); // Fix arguments - make them UTF-8 if(argc!=2) { boost::nowide::cerr << "Usage: file_name" << std::endl; // Unicode aware console return 1; } boost::nowide::ifstream f(argv[1]); // argv[1] - is UTF-8 if(!f) { // the console can display UTF-8 boost::nowide::cerr << "Can't open a file " << argv[1] << std::endl; return 1; } int total_lines = 0; while(f) { if(f.get() == '\n') total_lines++; } f.close(); // the console can display UTF-8 boost::nowide::cout << "File " << argv[1] << " has " << total_lines << " lines" << std::endl; return 0; }
=windows.h头文件=
本库并未包含windows.h,以免名字空间污染。本库自行定义了Win32 API函数的原型。
但是,如果你也想使用原生的windows.h头文件,你需要在包含Boost.Nowide头文件前设置BOOST_NOWIDE_USE_WINDOWS_H定义。
=技术细节=
1. Windows vs POSIX
Windows平台,本库在名字空间boost::nowide下提供UTF-8敏感的函数,通常情况下这些函数在名字空间std::下。
POSI平台,boost::nowide::fopen和所有其它函数都是标准库函数的别名:
namespace boost {
namespace nowide {
#ifdef BOOST_WINDOWS
inline FILE *fopen(char const *name,char const *mode)
{
...
}
#else
using std::fopen
#endif
} // nowide
} // boost
2. 控制台I/O
控制台I/O实现了ReadConsoleW/WriteConsoleW的封装,除非流不是“atty”的,例如管道。
这种方法排除了手工进行编码页处理。