因为项目需要,第一次接触到FTP的上传问题,经过查阅后摈弃了旧的QFtp,采用新的QNetworkAccessManager。有关它的使用其实也很方便,已经提供了比较成熟的接口和信号,下面总结一下。
首先,在头文件创建一些变量和指针
QUrl url;
QNetworkAccessManager *accessManager; //初始化为nullptr
QNetworkReply *reply; //初始化为nullptr
QFile *ftp_file; //初始化为nullptr
bool ftp_upload = false; //上传文件标识
bool ftp_download = false; //上传文件标识
url是之后需要上传的FTP服务器文件路径;QNetworkAccessManager 就是所谓的网络访问管理器,主要靠它来进行文件上传;QNetworkReply 是QNetworkAccessManager 上传时的一个回复对象,可以通过它来得到一些返回的信息
然后,是cpp文件中正式代码部分
//url
QUrl url(uploadUrl);//设置一个ftp路径,例如ftp://xxx/xx/x
url.setPort(ftp_upload_path_info.ftpport);//端口号
url.setUserName(ftp_upload_path_info.ftpaccount);//用户名
url.setPassword(ftp_upload_path_info.ftppws);//密码
//给指针添加实例
accessManager = new QNetworkAccessManager();
accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible);//设置可网络访问
QNetworkRequest request(url);//将QUrl设置进网络请求类QNetworkRequest 中
//该读取文件的方法,在1G以上的文件时会导致直接上传失败
//ftp_file = new QFile(filenamepath);
//ftp_file->open(QIODevice::ReadOnly);
//QByteArray byte_file = ftp_file->readAll();
//解决大文件的上传
QFile *data = new QFile(filenamepath,this);
if(data->open(QIODevice::ReadOnly))
{
}
reply = accessManager->put(request, data/*byte_file*/); //发送上传请求
connect(accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(loadError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(uploadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
代码不是很多,一步步来看。首先QUrl你要设置路径、端口号、用户名和密码,这是与FTP服务器相关的;然后就是正式的QNetworkAccessManager上传,你需要先把url设置进QNetworkRequest 对象中,再通过参数的形式传入QNetworkAccessManager的put方法中。put其实就是上传的意思,除了QNetworkRequest 参数外,你还需要一个文件指针。
这里有两种方法,网上主流的是先用QFile的readAll()来读取,但对于大文件是没办法readAll()的,所以会直接失败。这里将传入QByteArray 数据,改为直接传入QIODevice类型指针(QFile继承),从而解决大文件上传问题。亲测2G以上没问题,只是说文件越大上传速度肯定越慢嘛。
参考:解决QNetworkAccessManager实现ftp功能后,不能上传大于1G文件的问题
另外一个就是信号槽相关,这里我绑定了三条。第一条是QNetworkAccessManager本身的finished信号,这个不管是上传成功,还是上传失败,网络中断超时什么的都会返回,反正是一个结果,你需要通过QNetworkReply参数的错误参数来区分返回结果。
void xxx::replyFinished(QNetworkReply *)
{
qDebug()<<"reply->error()"<<reply->error();
if (reply->error() == QNetworkReply::NoError) //每个文件上传完成都执行
{
qDebug()<<"上传成功";
ftp_file->close();//文件操作要记得关闭
QMessageBox::about(NULL, "提示", "上传成功!");
}else if((reply->error() == QNetworkReply::OperationCanceledError))
{
//手动取消导致的错误
}
else
{
// QMessageBox::about(NULL, "提示", "上传失败!");
}
}
第二条信号槽也是报错信息,跟第一条类似,但报错时机可能会有区别
void xxx::loadError(QNetworkReply::NetworkError error)
{
qDebug()<<"Transmitted error!!!";
//QMessageBox::about(NULL, "提示", "上传失败!");
}
第三条信号槽就有点意思了,它是上传进度的一个反馈信号,uploadProgress(qint64 ,qint64)的参数分别是当前已上传大小和总大小,例如250,1000这样。
这个信号的触发频率适中,可以用它来做一个进度条的显示。例如用QProgressBar的void setRange(int minimum, int maximum);和void setValue(int value);来设置范围和当前值。
值得一提的是,这里的参数都是int型,而大文件上传的情况下,往往uploadProgress(qint64 ,qint64)的qint64 (long long)是大于int的,如果不自行判断换算一下的话,进度条会没有任何效果和百分比数值哦。
while(bytesTotal > 0x7fffffff)//int的最大值
{
bytesTotal /= 10;
bytesSent /= 10;
}