使用 MSVC 在 Windows 上将“\n”重新解释为 UTF16

Reinterpreting "\n" to UTF16 on Windows with MSVC

提问人:Jacob 提问时间:10/13/2023 更新时间:10/13/2023 访问量:98

问:

我正在尝试编写简单的程序,将大的 txt 文件划分为较小的文件。当涉及到 UTF16 编码文件时,问题就开始了。无论我如何尝试,例如,如果我们在 UTF16 LE 文件行中以“0D 00 0A 00”结尾,在除法后它是“0D 00 0D 0A 00”,或者如果是 UTF16 BE“00 0D 00 0A”,它会变成“00 0D 00 0D 0A”。这意味着每次我都要保存“0D 0A”字节。在评论中尝试了不同的方法,如下所示。我唯一的想法是在二进制模式下运行,不想使用 std 以外的其他库。任何线索都值得赞赏。

std::wifstream winfile;
std::wofstream woutfile;
using namespace std;

int main()
{
    std::wstring line, temp;
    unsigned int limit;
    unsigned int part = 1;

    //(...)
    
    while (!winfile.eof()) {
        limit = 1000000;
        woutfile.open(save_path + std::to_string(part) + ".txt", std::ios::out | std::ios::app);
        limit--;
        while (limit > 0 && !winfile.eof()) {
            getline(winfile, temp);
            wchar_t lf[]{ L'\n'};
            woutfile << temp << lf;   
            /*
            wchar_t lf[]{ 0x00, 0x0D, 0x00, 0x0A};
            woutfile << temp << lf;
            
            woutfile << temp << L"\n";
            woutfile << temp << std::endl;
            */
            
            limit--;
        }
        part++;
        winfile.close();
        woutfile.close();
    }
    system("pause");
}
C 文件 Visual-C++ 字符编码

评论

1赞 001 10/13/2023
以二进制模式打开文件,然后 ??write("\r\n", 2)
3赞 Brian61354270 10/13/2023
旁注:您可能对以下内容感兴趣 为什么 iostream::eof 在循环条件中(即 while (!stream.eof()))被认为是错误的?
2赞 n. m. could be an AI 10/13/2023
wchar_t lf[]{ L'\n'}; woutfile << temp << lf;是一个错误和未定义的行为。 根本没有做任何事情(它是一个空字符串)。wchar_t lf[]{ 0x00, 0x0D, 0x00, 0x0A}; woutfile << temp << lf;lf
0赞 n. m. could be an AI 10/13/2023
更糟糕的是,宽字符 C++ 流不会读取或写入 UTF-16 编码的文件。
0赞 Remy Lebeau 10/13/2023
@n.m.couldbeanAI,如果你用UTF-16,他们应该imbue()std::locale

答:

0赞 Adrian McCarthy 10/13/2023 #1

我们可以看到您的输出流处于文本模式。听起来您的输入流处于二进制模式(或者它是 UTF-16 的事实搞砸了对行尾的解释)。

使用二进制输入,您将读取回车符 (CR) 和换行符 (LF) 字符。

std::getline 的默认分隔符是 ,它恰好是几乎所有实现中的换行符。因此,getline 将回车符视为另一个字符,并在换行符处划分行。因此,生成的字符串以回车符结束,您将其写回。然后,在行后写入,并且由于输出流处于文本模式,因此该流被转换为CR+LF。因此,输出字符串以 CR+CR+LF 结尾。'\n''\n'

您可以通过以下几种方式处理此问题:

  • 以文本模式打开输入,如有必要,按照注释中建议@RemyLebeau进行输入。

  • 在二进制模式下执行所有操作。

  • 保持一切不变,但在将每行发送到输出流时跳过任何尾随回车。

评论

0赞 Jacob 10/13/2023
我没有使用二进制模式,所以读取问题来自源文件是 UTF-16 编码的。我将尝试使用 imbue 和 std::locale,否则二进制模式和使用 endianess 进行处理是解决方案。第三个命题是行不通的,我会向左剪掉 0D00 或 000D,但用任何方法保存的 CRLF 仍然是错误的,我也试过了。