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

从CArchive读取CString到QString(QDataStream)时遇空值问题

解决方案:从CArchive序列化的CString读取并转换为QString

问题核心在于CArchive序列化CString的格式和QDataStream序列化QString的格式完全不兼容,直接用>>操作符读取会导致解析错误。以下是具体解决步骤和代码:

关键前提:明确旧数据的编码类型

旧MFC程序编译时分为两种编码模式:

  • Unicode模式(VS默认):CString以UTF-16LE宽字节存储,序列化时先写4字节int类型的字符数,再写对应长度的宽字节数据(无结尾\0)
  • ANSI模式(旧版MBCS):CString以系统多字节编码存储,序列化时先写4字节int类型的字符数,再写对应长度的单字节数据(无结尾\0)

通用读取步骤

  1. 先设置QDataStream的字节序为小端(Windows平台默认小端,和CArchive一致)
  2. 手动读取CString的长度和原始字节数据,再转换为QString

针对Unicode版本CString的读取代码

int readData(QDataStream &ar)
{
    // 必须先设置字节序为小端,否则int长度会解析错误
    ar.setByteOrder(QDataStream::LittleEndian);

    // 读取age,这部分逻辑正确
    ar.readRawData(reinterpret_cast<char*>(&age), sizeof(age));

    // 读取name字段
    int nameLen;
    // 先读4字节的字符长度
    ar.readRawData(reinterpret_cast<char*>(&nameLen), sizeof(nameLen));
    // 读取对应长度的UTF-16LE字节数据
    QByteArray nameBytes(nameLen * sizeof(wchar_t), 0);
    ar.readRawData(nameBytes.data(), nameLen * sizeof(wchar_t));
    // 转换为QString
    name = QString::fromUtf16(reinterpret_cast<const ushort*>(nameBytes.constData()), nameLen);

    // 读取initial字段,逻辑和name完全一致
    int initialLen;
    ar.readRawData(reinterpret_cast<char*>(&initialLen), sizeof(initialLen));
    QByteArray initialBytes(initialLen * sizeof(wchar_t), 0);
    ar.readRawData(initialBytes.data(), initialLen * sizeof(wchar_t));
    initial = QString::fromUtf16(reinterpret_cast<const ushort*>(initialBytes.constData()), initialLen);

    // 读取height
    ar.readRawData(reinterpret_cast<char*>(&height), sizeof(height));

    // 其他业务逻辑...
    return 0;
}

针对ANSI版本CString的读取代码

如果旧程序是MBCS编码编译,需将字节转换为对应系统编码的QString(比如GBK、Windows-1252,根据旧程序运行的系统编码调整):

int readData(QDataStream &ar)
{
    ar.setByteOrder(QDataStream::LittleEndian);

    ar.readRawData(reinterpret_cast<char*>(&age), sizeof(age));

    // 读取name字段
    int nameLen;
    ar.readRawData(reinterpret_cast<char*>(&nameLen), sizeof(nameLen));
    QByteArray nameBytes(nameLen, 0);
    ar.readRawData(nameBytes.data(), nameLen);
    // 用旧程序对应的ANSI编码转换,这里以GBK为例,可替换为fromLatin1等
    name = QString::fromLocal8Bit(nameBytes);

    // 读取initial字段
    int initialLen;
    ar.readRawData(reinterpret_cast<char*>(&initialLen), sizeof(initialLen));
    QByteArray initialBytes(initialLen, 0);
    ar.readRawData(initialBytes.data(), initialLen);
    initial = QString::fromLocal8Bit(initialBytes);

    ar.readRawData(reinterpret_cast<char*>(&height), sizeof(height));

    return 0;
}

为什么原有方法无效?

  • 直接用ar >> name;:QDataStream会按照自身的QString序列化格式解析(先读quint32字节数+UTF-16字节),和CArchive的格式不匹配,必然读空或乱码
  • 用readRawData(&name, sizeof(name)):QString是类对象,sizeof(name)是对象本身的内存大小(约24字节),而非字符串长度,读取的是无关垃圾数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 02:05:16