You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下MSVC环境中UTF-16文件换行符处理异常问题

UTF-16编码TXT文件分割时换行符异常的解决思路

问题描述

处理UTF-16编码的大文件分割时,出现换行符异常:

  • 原UTF-16 LE文件中的换行符0D 00 0A 00,分割后变为0D 00 0D 0A 00
  • 原UTF-16 BE文件中的换行符00 0D 00 0A,分割后变为00 0D 00 0D 0A
    每次写入都会额外添加0D 0A字节。要求仅使用标准库,且采用二进制模式处理。

原始代码

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");
}

解决思路

1. 禁用文本模式的自动换行转换

核心问题在于默认的文本模式会自动将换行符在\n和系统原生换行(Windows下为\r\n)之间转换,这会破坏UTF-16编码的字节结构。必须用二进制模式打开文件,彻底禁用这种自动转换:

// 打开输入流时添加二进制标志
winfile.open(input_file_path, std::ios::in | std::ios::binary);
// 打开输出流时添加二进制标志
woutfile.open(save_path + std::to_string(part) + ".txt", std::ios::out | std::ios::binary);

2. 正确处理UTF-16的换行符

getline默认会吃掉行尾的\r(文本模式下\r\n被视为单个换行符),导致手动添加\n时,原有的\r加上新增的\n,再叠加文本模式的自动转换,最终出现重复的\r。

二进制模式下,直接写入UTF-16对应的换行符组合L"\r\n"即可,编码后的字节序列就是正确的0D 00 0A 00(LE)或00 0D 00 0A(BE):

// 替换原有的换行写入逻辑
woutfile << temp << L"\r\n";

3. 修复输入流的循环逻辑

原代码中winfile.close()放在外层循环内,第一次循环后就关闭了输入流,后续循环无法读取数据。要将输入流的打开和关闭移到外层循环外:

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

    winfile.open(input_file_path, std::ios::in | std::ios::binary);
    if (!winfile.is_open()) {
        // 处理文件打开失败的情况
        return 1;
    }
    
    while (!winfile.eof()) {
        limit = 1000000;
        woutfile.open(save_path + std::to_string(part) + ".txt", std::ios::out | std::ios::binary);
        if (!woutfile.is_open()) {
            // 处理输出文件打开失败的情况
            winfile.close();
            return 1;
        }
        
        limit--;
        while (limit > 0 && !winfile.eof()) {
            getline(winfile, temp);
            woutfile << temp << L"\r\n";
            limit--;
        }
        
        part++;
        woutfile.close();
    }
    
    winfile.close();
    system("pause");
    return 0;
}

4. 处理UTF-16的字节序(可选)

如果需要兼容UTF-16 BE和LE,可以通过读取文件开头的BOM(字节顺序标记)判断字节序,再用codecvt facet正确解码:

#include <locale>
#include <codecvt>

// 读取BOM后设置对应的编码转换
std::wstring_convert<std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>> le_conv;
std::wstring_convert<std::codecvt_utf16<wchar_t, 0x10ffff, std::big_endian>> be_conv;
// 根据BOM选择对应的转换器处理数据

内容的提问来源于stack exchange,提问作者Jacob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 19:32:49