公司开发的聊天软件,以前开发人员写的代码,超过100M的文件,就基本上崩溃,开发人员走了,无奈作为老板我只能自己修改。改完测试发送650M甚至更大文件没问题,稳定。
解决思路:
将http的post内容为 multipart/form-data 格式的,进行 格式准备,准备好的先 存到一个临时文件,再发送。以前存到一个 QByteArray 变量里,尽管按QT资料说能存2GB,但实际测试就是一存就崩,改为临时文件,当post时,第二个参数直接用文件IO就好了。
临时文件产生过程也要注意,以前直接读取全部要发的文件内容,超过200M也会崩,改为一次读写10M就好了。
为了避免临时文件造成磁盘空间占用,发送成功后的回调函数里要删除临时文件。
为了能支持多窗口同时发送多个文件,临时文件命名要使用随机数。
另外这个 缓存文件变量 m_file_tmp 要定义到 类成员里,我临时创建的缓存文件变量就不行,post时会崩。
bool ChatTransferFileThread::start()
{
QString strfilename = m_strFilePath;
QString strfile = "file";
if(m_strFilePath.isEmpty() || m_strServerAddr.isEmpty())
{
return false;
}
m_file.setFileName(m_strFilePath);
qDebug() << QString::fromLocal8Bit("上传文件名字")<< m_strFilePath;
if (!m_file.open(QIODevice::ReadOnly)||!m_file.exists())
{
QMessageBox::about(NULL, QString::fromLocal8Bit("错误提示"), m_strFilePath+QString::fromLocal8Bit("文件是空文件或是文件夹"));//卢伟华
/*QMessageBox message_cd(QMessageBox::NoIcon,QString::fromUtf8("警告"),QString::fromUtf8("您是否要关闭此软件?"));
message_cd.addButton(QString::fromUtf8("是"), QMessageBox::AcceptRole);
message_cd.addButton(QString::fromUtf8("否"), QMessageBox::RejectRole);
if(message_cd.exec() == QMessageBox::AcceptRole)
{
m_file->close();
this->close();
event->accept();
}
else
{
event->ignore();
}*/
m_file.close();
return false;
}
//qDebug()<<"m_strJessionId"<<m_strJessionId;
QNetworkCookie netWorkCookie = QNetworkCookie(QString("JSESSIONID1").toLatin1(), QString(m_strJessionId).toLatin1());
QVariant var;
var.setValue(netWorkCookie);
QByteArray fdata = QByteArray();
QByteArray fdata_tail = QByteArray();
QString strBoundary = "--------------------------------------adf70as00sd0fsf";
QMap<QString,QString> params;
params.insert("UPLOAD_MODE", "0");
params.insert("DURATION", "0");
params.insert("DEST_UID", "1");
qDebug() << QString::fromLocal8Bit("准备上传1");
for(QMap<QString,QString>::Iterator t=params.begin();t!=params.end();t++)
{
fdata.append("--"+strBoundary+"\r\n");
fdata.append(QString("Content-Disposition: form-data; name=\"")+t.key()+QString("\"")+QString("\r\n"));
fdata.append("\r\n");
fdata.append(t.value()+"\r\n");
}
//上传文件的头部
fdata.append("--"+strBoundary+"\r\n");
fdata.append(QString("Content-Disposition: form-data; name=\"")+strfile+QString("\"; filename=\"")+strfilename+QString("\"")+QString("\r\n"));
fdata.append(QString("Content-Type: multipart/form-data")+QString("\r\n"));
fdata.append("\r\n");
qDebug() << QString::fromLocal8Bit("准备上传2");
//生成缓存文件
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
QString tmp_file_path=QDir::tempPath()+"/oa_upload"+QString::number(qrand())+".tmp";
qDebug()<<QString::fromLocal8Bit("准备缓存文件") << tmp_file_path;
m_file_tmp.setFileName(tmp_file_path);
m_file_tmp.open(QIODevice::WriteOnly);
m_file_tmp.write(fdata);
//fdata.append(m_file.readAll());
//m_file_tmp.write(m_file.readAll());
while (!m_file.atEnd())
{
m_file_tmp.write(m_file.read(10000000));
}
qDebug() << QString::fromLocal8Bit("准备上传3");
//---------------------------
fdata_tail.append("\r\n");
fdata_tail.append("--"+strBoundary+"\r\n");
fdata_tail.append(QString("Content-Disposition: form-data; name=\"upload\"")+QString("\r\n"));
fdata_tail.append("\r\n");
fdata_tail.append("1\r\n");
fdata_tail.append("--"+strBoundary+"--\r\n");
m_file_tmp.write(fdata_tail);
m_file_tmp.close();
qDebug() << QString::fromLocal8Bit("准备上传4");
//int fdata_length=fdata.length();
QNetworkRequest request = QNetworkRequest(QUrl(m_strServerAddr));
request.setHeader(QNetworkRequest::CookieHeader, var);
request.setRawHeader(QString("Content-Type").toLatin1(),QString("multipart/form-data; boundary="+strBoundary).toLatin1());
//request.setRawHeader(QString("Content-Length").toLatin1(),QString::number(fdata_length).toLatin1());
//request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
if(m_pNetWorkManager == NULL)
{
return false;
}
qDebug() << QString::fromLocal8Bit("开始上传post")<<m_strServerAddr;
//m_pNetworkReply = m_pNetWorkManager->post(request, fdata);
m_file_tmp.open(QIODevice::ReadOnly);
m_pNetworkReply = m_pNetWorkManager->post(request,&m_file_tmp);
connect(m_pNetworkReply, &QNetworkReply::uploadProgress, this, &ChatTransferFileThread::onUploadProgress);
return true;
}