从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)
通用读取步骤
- 先设置QDataStream的字节序为小端(Windows平台默认小端,和CArchive一致)
- 手动读取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
相关产品推荐
相关产品推荐

