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

Qt中如何拆分含多JPG的QByteArray并还原单张图片?

多图片Blob存储与拆分问题的解决方案

问题根源

你用$作为分隔符合并图片字节的思路根本行不通——JPG这类二进制文件的字节流里完全可能包含$字符,拆分时自然会把图片内容里的$当成分隔符,导致拆分出一堆无效数据。


方案一:彻底修改存储方式(首推)

这是从根源解决问题的办法,分两种实现思路:

1. 每张图片单独存一条记录

直接在SQLite表里给每张图片单独建一行,比如表结构可以设为:

CREATE TABLE images (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    image_blob BLOB NOT NULL,
    -- 其他字段:比如图片名称、上传时间等
);

存储时循环处理用户选中的每张图片,把单张图片的QByteArray直接作为image_blob字段插入数据库;读取时直接查询对应行的image_blob,拿到的就是完整的单张图片字节流,完全不需要拆分,这是最稳妥、最易维护的方式。

2. 用长度前缀法合并存储(必须合并到同一Blob时用)

如果业务上必须把多张图片存在同一个Blob字段里,别用字符分隔,改用固定长度的长度前缀:存储每张图片前,先写入该图片的字节长度(比如用4字节无符号整数,统一字节序),再写入图片本身的字节数据,所有图片依次叠加。

存储合并代码示例:

QByteArray combineImages(const QList<QByteArray>& imageList) {
    QByteArray combinedData;
    QDataStream stream(&combinedData, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian); // 统一小端字节序,避免跨平台问题

    for (const auto& imgData : imageList) {
        quint32 imgLen = static_cast<quint32>(imgData.size());
        stream << imgLen; // 写入图片长度
        stream.writeRawData(imgData.constData(), imgLen); // 写入图片字节
    }

    return combinedData;
}

拆分还原代码示例:

QList<QByteArray> splitImages(const QByteArray& combinedData) {
    QList<QByteArray> imageList;
    QDataStream stream(combinedData);
    stream.setByteOrder(QDataStream::LittleEndian);

    while (!stream.atEnd()) {
        quint32 imgLen;
        stream >> imgLen;

        // 检查数据流是否正常
        if (stream.status() != QDataStream::Ok) {
            break;
        }

        QByteArray imgData;
        imgData.resize(imgLen);
        stream.readRawData(imgData.data(), imgLen);

        // 确保读取到完整的图片数据
        if (imgData.size() == imgLen) {
            imageList.append(imgData);
        }
    }

    return imageList;
}

方案二:临时处理已用$存储的旧数据(仅救急)

如果已经有一批用$分隔的旧数据需要导出,只能针对JPG格式做临时处理——利用JPG的结束标记0xFFD9来辅助判断:遍历字节流,每次找到0xFFD9后,检查后面是否紧跟$,如果是,就把从上次起始位置到0xFFD9的部分作为一张图片,跳过$继续找下一个。

注意:这种方法只适用于JPG,而且容错率极低(比如图片内容里意外出现0xFFD9就会误判),只能用来导出旧数据,之后必须换成方案一的存储方式。

代码示例:

QList<QByteArray> splitJpgFromDollarSeparated(const QByteArray& combinedData) {
    QList<QByteArray> imageList;
    int startPos = 0;
    const char* dataPtr = combinedData.constData();
    int totalLen = combinedData.size();

    for (int i = 0; i < totalLen - 1; ++i) {
        // 匹配JPG结束标记 0xFF 0xD9
        if (dataPtr[i] == 0xFF && dataPtr[i+1] == 0xD9) {
            // 检查下一个字符是否是分隔符$
            if (i + 2 < totalLen && dataPtr[i+2] == '$') {
                imageList.append(combinedData.mid(startPos, i + 2 - startPos));
                startPos = i + 3; // 跳过$,从下一个字节开始
                i += 2; // 跳过已处理的结束标记和分隔符
            }
        }
    }

    // 处理最后一张没有结尾$的图片
    if (startPos < totalLen) {
        imageList.append(combinedData.mid(startPos));
    }

    return imageList;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:09:29