如何将std :: wstring写入文件?

时间:2010-10-29 16:31:49

标签: c++ file unicode wstring wofstream

我声明了wstring

// random wstring
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

文字将是UTF-8编码,因为我的源文件是。

[编辑:根据Mark Ransom的说法不一定是这样,编译器将决定使用什么编码 - 让我们假设我从例如编码的文件中读取该字符串。 UTF-8]

我非常希望将其转换为文件读取(当文本编辑器设置为正确的编码时)

abcàdëefŸg€hhhhhhhµa

但是ofstream不是很合作(拒绝接受wstring个参数),wofstream据说需要知道区域设置和编码设置。我只想输出这组字节。通常如何做到这一点?

编辑:它必须是跨平台的,不应该依赖于UTF-8 的编码。我碰巧有一组字节存储在wstring中,并希望输出它们。它很可能是UTF-16,或纯ASCII。

9 个答案:

答案 0 :(得分:29)

对于std::wstring,您需要std::wofstream

std::wofstream f(L"C:\\some file.txt");
f << str;
f.close();

答案 1 :(得分:14)

std::wstring适用于UTF-16或UTF-32,不是 UTF-8。对于UTF-8,您可能只想使用std::string,并通过std::cout写出来。只是FWIW,C ++ 0x将具有Unicode文字,这应该有助于澄清这样的情况。

答案 2 :(得分:7)

为什么不将文件写为二进制文件。只需在std :: ios :: binary设置中使用ofstream即可。编辑应该能够解释它。不要忘记开头的Unicode标志0xFEFF。 你最好用图书馆写作,试试其中一个:

http://www.codeproject.com/KB/files/EZUTF.aspx

http://www.gnu.org/software/libiconv/

http://utfcpp.sourceforge.net/

答案 3 :(得分:4)

C ++具有在输出或文件写入时执行从宽字符到本地字符的转换的方法。 Use为此目的的codecvt方面。

您可以使用标准std::codecvt_byname或非标准codecvt_facet implementation

#include <locale>
using namespace std;
typedef codecvt_facet<wchar_t, char, mbstate_t> Cvt;
locale utf8locale(locale(), new codecvt_byname<wchar_t, char, mbstate_t> ("en_US.UTF-8"));
wcout.imbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

请注意,在某些平台上,codecvt_byname只能为系统中安装的区域设置发出转换。因此,我建议在stackoverflow中搜索“utf8 codecvt “并从列出的自定义codecvt实现的许多参考资料中做出选择。

编辑: 由于OP声明字符串已经编码,他应该做的就是从代码的每个标记中删除前缀L和“w”。

答案 4 :(得分:2)

有一个(特定于Windows的)解决方案应该适合您here。基本上,将wstring转换为UTF-8代码页,然后使用ofstream

#include < windows.h >

std::string to_utf8(const wchar_t* buffer, int len)
{
        int nChars = ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                NULL,
                0,
                NULL,
                NULL);
        if (nChars == 0) return "";

        string newbuffer;
        newbuffer.resize(nChars) ;
        ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                const_cast< char* >(newbuffer.c_str()),
                nChars,
                NULL,
                NULL); 

        return newbuffer;
}

std::string to_utf8(const std::wstring& str)
{
        return to_utf8(str.c_str(), (int)str.size());
}

int main()
{
        std::ofstream testFile;

        testFile.open("demo.xml", std::ios::out | std::ios::binary); 

        std::wstring text =
                L"< ?xml version=\"1.0\" encoding=\"UTF-8\"? >\n"
                L"< root description=\"this is a naïve example\" >\n< /root >";

        std::string outtext = to_utf8(text);

        testFile << outtext;

        testFile.close();

        return 0;
}

答案 5 :(得分:0)

请注意,宽流只输出char *变量,因此您可以尝试使用c_str()成员函数转换std::wstring,然后将其输出到文件中。它应该可行吗?

答案 6 :(得分:0)

前段时间我遇到了同样的问题,并写下了我在博客上找到的解决方案。您可能需要查看它是否有帮助,尤其是函数wstring_to_utf8

http://pileborg.org/b2e/blog5.php/2010/06/13/unicode-utf-8-and-wchar_t

答案 7 :(得分:0)

如果要编写可移植代码,则应使用UTF-8编码的源文件。遗憾。

  std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

(我不确定这是否真的会伤害标准,但我认为是。但即使是安全的,也不应该。)

是的,纯粹使用std::ostream将无效。有很多方法可以将wstring转换为UTF-8。我最喜欢的是使用 International Components for Unicode 。这是一个很大的库,但它很棒。你会得到很多额外的东西以及将来可能需要的东西。

答案 8 :(得分:0)

根据我使用不同角色编码的经验,我建议您只在加载时处理UTF-8并节省时间。如果您尝试将内部表示存储在UTF-8中,那么您将陷入痛苦的世界,因为单个字符可以是1字节到4之间的任何内容。因此像strlen这样的简单操作需要查看每个字节来决定len而不是分配缓冲区(尽管您可以通过查看char序列中的第一个字节进行优化,例如00..7f是单字节char,c2..df表示2字节char等)。

当人们经常提到'Unicode字符串'时,他们指的是UTF-16,而在Windows上,wchar_t是固定的2字节。在Windows中,我认为wchar_t只是:

typedef SHORT wchar_t;

完整的UTF-32 4字节表示很少需要且非常浪费,这就是Unicode标准(5.0)所说的:

“平均超过99%的UTF-16使用单一代码单位表示...... UTF-16提供紧凑尺寸的正确组合,能够处理BMP之外的偶然角色”

简而言之,使用whcar_t作为内部表示并在加载和保存时进行转换(除非您知道需要,否则不要担心完整的Unicode)。

关于执行实际转换,请查看ICU项目:

http://site.icu-project.org/