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

QXmlStreamWriter的writeCharacters写入大文件到QBuffer时崩溃求解决

问题描述

在Qt 4.8.7(Visual Studio 2010、Windows 10环境)中,使用QXmlStreamWriter通过小缓冲区调用writeCharacters()写入大文件内容时:

  • 写入本地XML文件可正常运行
  • 写入QBuffer时writeCharacters()会崩溃

相关代码如下:

测试主函数

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QXmlStreamWriter>
#include <QBuffer>

int main(int argc, char *argv[])
{
   
    QCoreApplication a(argc, argv);

    QByteArray mContentBuffer;
    QByteArray arr;
    int pos, filesize;

    QFile file("C:\\Work\\bigfile.xar"); // 大小:300Mb

    if(!file.open(QFile::ReadOnly))
    {
        return -1;
    }

    mContentBuffer = file.readAll();
    file.close();

    //QFile profile("C:\\Work\\profile.xml");

    //if(!profile.open(QFile::WriteOnly|QFile::Truncate))
    //{
    //    return -1;
    //}
    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);

    QXmlStreamWriter stream(&buffer);    

    stream.setAutoFormatting(true);
    stream.writeStartDocument();
    stream.writeStartElement("Profile");

    //stream.writeTextElement("Content", mContentBuffer.toBase64());
    stream.writeStartElement("Content");
    pos = 0; 
    filesize = mContentBuffer.size();         
    while(pos<filesize){
       arr = mContentBuffer.mid(pos, 2000000);
       stream.writeCharacters(arr.toBase64());
       pos+=arr.size();
    }
    stream.writeEndElement();
    stream.writeEndElement(); // Profile
    stream.writeEndDocument();

    return 0;
}

目标业务函数

bool profileModified()
{
    bool result = true;

    QFile profile("C:\\Work\\profile.xml");
    if(profile.exists())
    {
        QBuffer buffer;
        buffer.open(QBuffer::ReadWrite);
        QXmlStreamWriter stream(&buffer);
        
        exportProfile(stream);

        profile.open(QFile::ReadOnly);
        QByteArray profileArr = profile.readAll();
    
        buffer.seek(0);
      
        QByteArray bufferArr = buffer.buffer();
         
        result = (array_compare(profileArr, bufferArr) != 0);
        
        profile.close();
    }

    return result;
}
解决方案

崩溃原因分析

Qt 4.8.7的QXmlStreamWriter在处理QBuffer这类内存设备时,内部缓冲区管理存在缺陷:当写入超大量数据时,内存缓冲区的扩容逻辑可能触发越界访问或内存分配失败,进而导致崩溃。而写入本地文件时,数据会被及时刷入磁盘,不会在内存中累积过大的缓冲区,因此不会触发该问题。

具体修复方案

  1. 禁用自动格式化
    自动格式化(setAutoFormatting(true))会额外生成大量空白字符,大幅增加内存占用,是触发崩溃的重要诱因。将其改为stream.setAutoFormatting(false),减少内存压力。

  2. 优化QBuffer的初始化方式
    提前预分配足够的内存空间给QBuffer,避免频繁扩容:

    QByteArray bufferData;
    // 预估算所需空间:原文件Base64编码后体积约为原大小的1.33倍,再加上XML标签的额外开销
    bufferData.reserve(mContentBuffer.size() * 2); 
    QBuffer buffer(&bufferData);
    buffer.open(QBuffer::ReadWrite);
    
  3. 改用临时文件替代QBuffer
    如果内存压力仍然过大,可以用临时文件代替内存缓冲区,避免一次性占用大量内存:

    bool profileModified()
    {
        bool result = true;
        QFile profile("C:\\Work\\profile.xml");
        if(profile.exists())
        {
            // 使用临时文件替代QBuffer
            QTemporaryFile tempFile;
            if (!tempFile.open()) {
                return false;
            }
            QXmlStreamWriter stream(&tempFile);
            exportProfile(stream);
            tempFile.flush();
            tempFile.seek(0);
    
            profile.open(QFile::ReadOnly);
            QByteArray profileArr = profile.readAll();
            QByteArray tempArr = tempFile.readAll();
            
            result = (array_compare(profileArr, tempArr) != 0);
            
            profile.close();
        }
        return result;
    }
    
  4. 升级Qt版本(可选)
    该问题在Qt 5.x及以上版本中已被修复,若项目允许,升级到更高版本的Qt可以从根源解决此类内存管理问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 07:35:16