【问题标题】:type in special characters and save in file [duplicate]输入特殊字符并保存在文件中[重复]
【发布时间】:2018-09-29 03:39:17
【问题描述】:

我想使用纯文本文件来保存来自用户的输入,以便稍后读出。在应用程序中,可能会出现德语和西班牙语的特殊符号。不幸的是,下面的代码没有将标志正确地保存在文件中。如何最好地解决这个问题?

我在 C 中的一个类似应用程序中通过保存在 .bin 文件而不是 .txt 中解决了这个问题,但是在 c++ 中没有更好的解决方案吗?

#include <string>
#include <fstream>
#include <iostream>

int main() {


    std::string s = "abcöäüÑ"; //(alt + 165 for Ñ)
    std::ofstream ofs{ "test.txt" };
    ofs << s <<'\n';            //this works fine  "abcöäüÑ"


    std::string s2;
    std::cin >> s2;     //typeing in the app abcöäüÑ   (alt+165 for Ñ)
    // i use a windows system with a german keyboard setting

    ofs << s2 <<'\n';       //this doesn't it gets   "abc”„¥"
}

我使用带有德语键盘设置的 Visual Studio 2017 的 windows 7 64 系统。

【问题讨论】:

    标签: c++ windows visual-c++ unicode


    【解决方案1】:

    最简单的解决方案(已弃用)是使用德语的 ANSI 代码页:

    setlocale(LC_ALL, "gr");
    cout << "abcöäüÑ\n";
    
    ofstream fout("ansi.txt");
    fout << "abcöäüÑ\n";
    

    这适用于一些有限的字符集,如果你坚持使用西方拉丁字符,它是相对安全的。也许这就是您使用 C 代码所做的。它与将文件保存为二进制或文本没有太大关系。

    在 Windows 中,建议将 Unicode 与宽字符串函数一起使用。示例:

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <codecvt>
    #include <io.h>
    #include <fcntl.h>
    
    int main() 
    {
        _setmode(_fileno(stdout), _O_U16TEXT);//wcout instead of cout
        _setmode(_fileno(stdin), _O_U16TEXT); //wcin  instead of cin
        std::locale loc_utf16(std::locale(), new std::codecvt_utf16<wchar_t>);
    
        std::wofstream fout(L"utf16.txt", std::ios::binary);
        if(fout)
        {
            fout.imbue(loc_utf16);
            fout << L'\xFEFF'; //insert optional BOM for UTF16
            fout << L"abcöäüÑ ελληνική\r\n";
            fout.close();
        }
    
        std::wifstream fin(L"utf16.txt", std::ios::binary);
        if(fin)
        {
            fin.imbue(loc_utf16);
            fin.seekg(2, std::ios::beg); //skip optional BOM if it were added
            std::wstring ws;
            while(std::getline(fin, ws)) std::wcout << ws << std::endl;
            fin.close();
        }
        return 0;
    }
    

    UTF16 的缺点是 Linux 等系统上的程序可能很难使用这种格式。有些人会将文件保存为 UTF8 格式,因为 UTF8 更熟悉其他系统。

    Windows 本身是基于 UTF16 的。所以你必须以 UTF16 读取和显示输入。但是您可以读取/写入 UTF8 格式的文件。示例:

    std::wcout << "enter:";
    std::wstring sw;
    std::wcin >> sw;
    
    std::locale loc_utf8(std::locale(), new std::codecvt_utf8<wchar_t>);
    std::wofstream fout(L"utf8.txt", std::ios::binary);
    if(fout)
    {
        fout.imbue(loc_utf8);
        fout << sw << L"\r\n";
        fout << L"abcöäüÑ ελληνική\r\n";
    }
    

    这里的二进制标志很重要。

    【讨论】:

    • 你能解释一下为什么你必须使用_setmode(_fileno(stdout), _O_U16TEXT);//wcout instead of cout _setmode(_fileno(stdin), _O_U16TEXT); //wcin instead of cin auto loc = std::locale(std::locale(), new std::codecvt_utf16&lt;wchar_t, 0x10ffff, std::little_endian&gt;());为什么它不能只使用 std::wstring, std::wcout 吗??
    • 我不知道控制台的内部工作原理,而且我认为您对那个解释不感兴趣。你可能会问“为什么默认不这样做?”原因是你在调用_setmode之后不能使用std::cout(除非你将模式重置回_O_TEXT)有人决定不打破cout 默认程序。 wfstream 有点复杂,但那是因为它可以同时支持 UTF8 和 UTF16。查看更新的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 2012-03-25
    • 2013-12-09
    相关资源
    最近更新 更多