[译][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”的,例如管道。
这种方法排除了手工进行编码页处理。

posted on 2015-10-08 10:41  zhcn  阅读(957)  评论(0编辑  收藏  举报

导航