将 unicode 字符/字符串写入文件

Posted

技术标签:

【中文标题】将 unicode 字符/字符串写入文件【英文标题】:writing unicode characters/string to file 【发布时间】:2019-09-04 04:14:54 【问题描述】:

我正在尝试使用 std::wofstream 将 unicode 字符写入文件,但 putwrite 函数不写入任何字符。

示例代码:

#include <fstream>
#include <iostream>

int main()

    std::wofstream file;
    file.open("output.txt", std::ios::app);
    if (file.is_open())
    
        wchar_t test = L'й';
        const wchar_t* str = L"фывдлао";
        file.put(test);
        file.write(str, sizeof(str));
        file.close();
    
    else
    
        std::wcerr << L"Failed to open file" << std::endl;
    

    std::cin.get();
    return 0;

output.txt文件为空,执行代码后没有写入wchar/string,为什么?我做错了什么?

编辑: 更正代码:

#include <fstream>
#include <iostream>

int main()

    std::wofstream file;
    file.open("output.txt", std::ios::app);
    if (file.is_open())
    
        wchar_t test = L'й';
        const wchar_t* str = L"фывдлао";
        file.put(test);
        if (!file.good())
        
            std::wcerr << L"Failed to write" << std::endl;
        
        file.write(str, 8);
        file.close();
    
    else
    
        std::wcerr << L"Failed to open file" << std::endl;
    

    std::cin.get();
    return 0;

应用代码更正后,我看到了Failed to write,但我仍然不明白我需要做什么才能编写宽字符串和字符?

【问题讨论】:

FWIW:C++ 中的宽字符存在问题,AFAIK wchar_t 可能会导致它解决的更多问题。替代实现,如 QString,可能是更安全的选择。 QString?当然必须有一种方法可以使用标准库或本机 OS API 使用 unicode 吗?我只是从未遇到过以意想不到的方式工作的广泛版本的函数/对象的问题。 IE。宽版本的 offstream 处理 char 而不是 wchar_t 这背后的逻辑是什么? @Frax QString 也是基于wchar_t。它的唯一优势是来自一个来源的稳定版本的 ABI。 @Deduplicator 一方面,QString 可以正确处理 UTF-8 并且开箱即用。一般来说,它是可移植的,而 wchar_t 则不是那么多,因为它在不同平台上具有不同的大小。我不确定它在实践中是如何工作的。关键是,cpp 标准几乎不能保证 wchar_t 是什么,而 QString 是非常具体的(即稳定的 ABI;实际上这是一个大问题)。 @Frax 对不起,我错了。 QString 是基于它们自己的 UTF-16 codeunit-class,而不是基于 wchar_t 【参考方案1】:

我让它这样工作,不需要外部字符串库,如 QString!

仅使用 std 库和 c++11

#include <iostream>
#include <locale>
#include <codecvt>
#include <fstream>
#include <Windows.h>

int main()

    std::wofstream file;
    // locale object is responsible of deleting codecvt facet!
    std::locale loc(std::locale(), new std::codecvt_utf16<wchar_t> converter);

    file.imbue(loc);
    file.open("output.txt"); // open file as UTF16!

    if (file.is_open())
    
        wchar_t BOM = static_cast<wchar_t>(0xFEFF);
        wchar_t test_char = L'й';
        const wchar_t* test_str = L"фывдлао";

        file.put(BOM);
        file.put(test_char);
        file.write(test_str, lstrlen(test_str));

        if (!file.good())
        
            std::wcerr << TEXT("Failed to write") << std::endl;
        

        file.close();
    
    else
    
        std::wcerr << TEXT("Failed to open file") << std::endl;
    

    std::wcout << TEXT("Done!") << std::endl;

    std::cin.get();
    return 0;

文件输出:

йфывдлао

【讨论】:

请注意,std::codecvt_utf16&lt;wchar_t&gt; 已被弃用,目前还没有替代品。您可以考虑将文件保存为 UTF8 格式,为 WinAPI 转换回 UTF16【参考方案2】:

第一个问题立即发生:put 无法写入宽字符,流将失败,但是您永远不会检查第一次写入是否成功:

file.put(test);
if(not file.good())

    std::wcerr << L"Failed to write" << std::endl;

第二个问题是 sizeof(str) 返回指针的大小(以字节为单位),而不是字符串的大小(以字节为单位)。

【讨论】:

谢谢,我更新了我的问题并进行了更正......我需要做什么来编写宽字符串?你说put 不接受宽字符,但我看到它期待wchar_t 的参数,因为它是wofstream 宽版本,那么为什么它不起作用? @zebanovich 尽管它是一个“宽”版本,但它仍然在“单个”字符上运行。所以写宽字符的唯一方法是以二进制模式打开文件并使用write 方法。 好的,我尝试了std::ios::binary 并且只使用了write 方法,但它仍然没有写出宽字符串。失败位已设置。 @zebanovich 你确定你已经在二进制模式下打开了普通流(不是每次宽字符不能缩小时都会失败的宽流)吗? 我也试过了,使用std::ofstream 的普通流会导致错误的输出。 warning C4244: 'argument': conversion from 'wchar_t' to '_Elem', possible loss of data

以上是关于将 unicode 字符/字符串写入文件的主要内容,如果未能解决你的问题,请参考以下文章

如何将unicode字符串写入文件? [复制]

使用 CodeGear C++ Builder 2009 将 unicode 字符串写入文件

如何将 unicode 写入 txt? Python [重复]

如何在 R Windows 中将 Unicode 字符串写入文本文件?

Python BeautifulSoup 在写入文件时创建奇怪的 \xe2 unicode 字符

如何从 Unicode 中的 CFile::Read() 文件中获取 CString 对象?