通过'unicode编码',我认为你的意思是UTF-16.实际上有几种编码可能被称为Unicode编码,但大多数不熟悉Unicode的人认为它是指UTF-16(我认为主要是因为微软在他们的所有文档中都犯了这个错误).我的回答还假设您正在为Windows编写代码,因此您的内部数据是以UTF-16存储在wchar_t字符串中.
使用宽流对象并不意味着文件输入或输出将使用宽字符完成.事实上,一个宽流将使用流的语言环境的codecvt方面,以便在流的字符类型(wchar_t)和char之间进行转换.
在C++ 11中,您可以使用一些codecvt方面来执行UTF-16或UTF-8输入/输出; codecvt_utf8,codecvt_utf16,codecvt_utf8_utf16.
codecvt_utf8将在外部UTF-8多字节序列和内部UTF-32/UCS4或UCS2数据之间进行转换.codecvt_utf16将在外部UTF-16多字节序列和内部UTF-32/UCS4或UCS2数据之间进行转换.codecvt_utf8_utf16将在外部UTF-8多字节序列和内部UTF-16数据之间进行转换.
没有内置的方法可以在外部UTF-16多字节序列和内部UTF-16数据之间进行转换,这是您在内部使用UTF-16编码的wchar_t字符串和外部使用UTF-16编码文件时所需要的.
但由于您表示UTF-8输出可以接受,因此codecvt_utf8_utf16 facet将运行良好.
#include <fstream>
#include <codecvt>
int main() {
std::wofstream mystream("test.txt");
mystream.imbue(std::locale(std::locale(),
new std::codecvt_utf8_utf16<wchar_t, 0x10ffff, std::codecvt_mode(std::consume_header|std::generate_header)>));
mystream << "Hello, World!\n";
}
Run Code Online (Sandbox Code Playgroud)
另请注意,此示例在codecvt_utf8_utf16 facet上设置选项以生成和读取所谓的"UTF-8 BOM".这是用于猜测文件编码的Microsoft约定,通常不适用于其他平台.
以下与手头的问题无关,但是facet的生命周期管理与大多数其他现代C++生命周期管理不同.
构面是引用计数的,当具有特定构面的最后一个区域设置被破坏时,将删除构面,除非通过构造具有refs参数的构面特别禁用了构面1.上面的示例代码将生命周期管理留给了语言环境,因此看起来类似于内存泄漏.但是,代码是正确的.在异常安全方面,唯一可能在成功分配和由语言环境假定的已分配对象的所有权之间运行的代码std::locale()是声明为noexcept 的表达式.
另一种选择是使用不受语言环境管理的构面,并简单地确保它比区域设置和所有副本更长.使用具有静态存储持续时间的构面很简单,但请记住,区域设置不应通过将其引用计数设置为1来删除构面.
static std::codecvt_utf8_utf16<wchar_t, 0x10ffff, std::codecvt_mode(std::consume_header|std::generate_header)> mycodecvt(1);
mystream.imbue(std::locale(std::locale(), mycodecvt));
Run Code Online (Sandbox Code Playgroud)
如果区域设置仅在特定范围内短时间存在,则可以使用普通的局部变量.这与上述相同但没有static.只需确保在构面超出范围之前销毁区域设置(以及每个副本).
这是智能指针不能使事情变得更好的一次,因为将所有权移交给智能指针不经意的对象是棘手的.您必须弄清楚如何手动处理在语言环境收到方面后发生的异常,因此在智能指针放弃所有权之前已经取得了所有权.
| 归档时间: |
|
| 查看次数: |
7778 次 |
| 最近记录: |