如何在C++中将文件内容读入char16_t数组?

3
您可以使用以下函数将文件内容读入到char数组中:
void readFileContentsIntoCharArray(char* charArray, size_t sizeOfArray) {
    std::ifstream inputFileStream;
    inputFileStream.read(charArray, sizeOfArray);
}

现在文件是以UTF-16LE编码的,所以我想将文件内容读入一个char16_t数组中,以便后续更方便地处理。我尝试了以下代码:

void readUTF16FileContentsIntoChar16Array(char16_t* char16Array, size_t sizeOfArray) {
    std::ifstream inputFileStream;
    inputFileStream.read(char16Array, sizeOfArray);
}

当然会没有效果。 std :: ifstream 不接受 char16_t 。我已经寻找解决方案很长时间了,但迄今为止发现的唯一相关方法是 https://dev59.com/-2PVa4cB1Zd3GeqP7Jrq#10504278 ,但它并没有提供太大帮助,因为它使用的是 wchar_t 而非 char16_t 。如何使用 char16_t 使其起作用?

你可以读取2*sizeOfArray字节,然后手动将每2个char转换为char16_t......如果架构是大端的话,你无法做得更好,如果是小端的话,你可以使用一些指针转换技巧。 - user202729
文件采用UTF-16LE编码,请在使用前进行转码,例如使用iconv。请告知文件制作者立即停止使用该编码方式,并改用UTF-8编码。 - n. m.
"std::ifstream无法接受char16_t类型。你需要将输入数组转换为“char *”类型。" - n. m.
2个回答

1
我已经创建了一个样本UTF-16LE文件,这段代码能够正确读取它。你可以试一试:
std::string readUTF16(const char* filename) {
    std::wifstream file(filename, std::ios::binary);
    file.imbue(std::locale(file.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));

    std::wstring ws;
    for(wchar_t c; file.get(c); ) {
        ws += (char16_t) c;
    }
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    return converter.to_bytes(ws);
}

它在Linux/macOS上无法处理代理对,会截断代理对并仅保留其中一个字节。 - Searene

1
你可以将字节读入char16_t数组,然后手动转换字节顺序(不同的架构在内存中以不同的顺序存储宽字符)。
为此,您必须能够检测正在运行的机器的字节顺序。
我在这个示例中使用了这个方法,但您可能希望使用具有可移植编译时检查的适当库版本。
bool is_little_endian()
{
    char16_t const c = 0x0001;
    return *reinterpret_cast<char const*>(&c);
}

然后你可以这样做:
std::u16string read_utf16le(std::string const& filename)
{
    // open at end to get size.
    std::ifstream ifs(filename, std::ios::binary|std::ios::ate);

    if(!ifs)
        throw std::runtime_error(std::strerror(errno));

    auto end = ifs.tellg();
    ifs.seekg(0, std::ios::beg);
    auto size = std::size_t(end - ifs.tellg());

    if(size % 2)
        throw std::runtime_error("bad utf16 format (odd number of bytes)");

    std::u16string u16;
    u16.resize(size / 2);

    if(u16.empty())
        throw std::runtime_error("empty file");

    if(!ifs.read((char*)&u16[0], size))
        throw std::runtime_error("error reading file");

    if(!is_little_endian())
    {
        // convert from big endian (swap bytes)
        std::transform(std::begin(u16), std::end(u16), std::begin(u16), [](char16_t c){
            auto p = reinterpret_cast<char*>(&c);
            std::swap(p[0], p[1]);
            return c;
        });
    }

    return u16;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接