我们不免有要通过Http下载一些文件的需求,开始的时候,也是通过在一个文件中编写很多的代码,但是当我们在其他的地方使用的时候,我们有时候又要重新编写一次。很是麻烦。我在想是否可以编写一个类库来实现通过Http下载文件的功能。经过一段时间的努力,终于实现了。下载的原理是,给一个下载的绝对路径,和要下载的目标地址,这样可以下载到临时目录中,当下载完成是,移动下载到临时目录中的文件到当前目录中(根据下载的文件,可以本地已经存在的文件进行备份)。核心代码如下:
- /******************************************************************************
- *
- * 文件名: HttpDownload.h
- *
- * 文件摘要: Http下载类
- *
- * 作者:程晓鹏
- *
- * 文件创建时间: 2011/09/05 11:28:35
- *
- *******************************************************************************/
- #ifndef HTTPDOWNLOAD_H
- #define HTTPDOWNLOAD_H
- #include <QFile>
- #include <QHttp>
- #include <QUrl>
- #include <QString>
- #include <QtNetwork>
- #include <QHttpResponseHeader>
- #include <QDebug>
- #include <QDir>
- #include <QMessageBox>
- /**
- * Http下载类
- *
- */
- class HttpDownload : public QObject{
-
- Q_OBJECT
- public:
-
- /**
- * 构造函数
- *
- * @param parent 父窗体ID
- *
- */
- HttpDownload(QObject* parent=0);
- /**
- * 进行下载
- *
- * @param url 下载的URL地址
- * @param target 下载目录,或者文件(默认为空,则下载在临时目录.tmp_down目录下)
- *
- * 说明:当该下载操作成功,仅将需要下载的文件下载到
- * 当前目录下的 .tmp_down临时目录中
- * (如果想更改临时目录的名称,需要在调用此方法前调用
- * setDownloadTempFloder(QString)方法,更改临时目录名称)
- *
- * 如果您需要将文件从临时目录中移动到当前目录中,
- * 并删除该临时目录,需要调用finishDownload方法。
- *
- * target参数,为下载的时文件所存放的路径
- * 如target为/update/down/ 则下载的文件将会在
- * 当前目录下创建update/down目录结构,(注意参数中的最后一定要带上‘/’)
- * 将url路径指定的文件保存在此目录下。
- *
- * 另外当target为 /update/down/test.jpg,
- * 则系同样会创建/update/down目录
- * 将url路径指定的文件保存在此目录下
- */
- void download(QUrl url, QString target = "");
- /**
- * 进行HTTP请求
- *
- * @param url 进行HTTP请求的URL
- * @requestData 请求的数据
- *
- * 说明:当调用该方法时,如果该方法执行成功,将会
- * 发出 getHttpResponse(QString response)信号
- */
- void beginHttpRequest(QUrl url, QString requestData = "");
- /**
- * 完成下载的文件
- *
- * 说明:将下载的文件进行替换操作 & 删除下载的文件
- *
- */
- void finishDownload();
- /**
- * 设置下载临时目录的名称
- *
- * @param folderName 目录的名称
- *
- * 备注:建议folderName为一级目录名称 如:tmp
- * 注意:不要和setBackupTempFolder设置为同一个名称
- */
- void setDownloadTempFolder(QString folderName = ".tmp_down");
- /**
- * 设置备份文件所在的目录
- *
- * @param folderName 目录的名称
- *
- * 备注:建议folderName为一级目录名称如:bak
- * 注意:不要和setDownloadTempFolder设置为同一个名称
- */
- void setBackupTempFolder(QString folderName = ".tmp_bak");
- /**
- * 备份文件
- *
- * @param filePath 文件的相对路径
- *
- * 说明:如果路径中存在目录,则自动创建相应的目录
- * 备注:此方法只能针对一个文件的相对路径,而不能针对多个文件
- */
- void backupFile(QString filePath);
- /**
- * 还原已经备份的文件
- *
- * 说明:还原备份的文件,删除备份文件的目录
- */
- void restoreBackupFiles();
- /**
- * 删除下载的临时文件
- *
- */
- void deleteDownloadTempFiles();
- /**
- * 获取文件名
- *
- * @param path 文件的路径
- *
- * @return 文件名
- */
- QString getFileName(QString path);
-
- /**
- * 析构函数
- *
- */
- ~HttpDownload();
- signals:
- /**
- * 下载文件的进度
- *
- * @param done 当前的下载量
- * @param total 下载的总量
- */
- void downloadProgress(int done, int total);
- /**
- * 获取HTTP请求的响应字符串
- *
- * @response HTTP响应字符串
- */
- void getHttpResponse(QString response);
- /**
- * 下载文件完成的信号
- *
- */
- void downFinish();
- private slots:
- /**
- * 当HTTP请求完成时
- *
- * @param requestID 请求的ID
- * @param error 返回请求是否成功
- */
- void httpRequestFinish(int requestID, bool error);
- /**
- * 当HTTP请求开始时
- *
- * @param resp HTTP响应头对象
- */
- void httpReadReady(const QHttpResponseHeader &resp);
- /**
- * 当HTTP请求开始下载文件时
- *
- * @param resp HTTP响应头对象
- */
- void httpDownloadReadReady(const QHttpResponseHeader &resp);
- private:
- QHttp *http;
- QHttp *httpDown;
- QFile *file;
- QHttpRequestHeader header;
- int httpid;
- QString strTmpDownDir; //定义下载文件的临时目录
- QString strBakDir; //定义备份文件所在的临时目录
- /**
- * 根据目录名称,获取带有'/'结束的目录名称
- *
- * @param folderName 目录名称
- *
- * @return 带有'/'结束的目录名称
- */
- QString getFolderName(QString folderName);
- QString getFolderPath(QString filePath);
- /**
- * 删除文件指针
- *
- * @param myfile 文件指针
- */
- void deleteFile(QFile *myfile);
- /**
- * 删除Http指针
- *
- * @param myhttp HTTP请求指针
- */
- void deleteHttp(QHttp *myhttp);
- /**
- * 初始化Http对象
- *
- * @param myhttp http指针
- * @url 连接的URL
- * @isNew 是否实例化myhttp
- */
- void initHttp(QHttp *myhttp, QUrl url, bool isNew);
- /**
- * 获取文件名
- *
- * @param url Http的Url
- *
- * @return 文件名
- */
- QString getFileName(QUrl url);
- /**
- * copy一个目录中的文件到另外一个目录
- *
- * @param fromDir 源目录
- * @param toDir 目标目录
- * @param coverFileIfExist 当目标目录中存在同名文件,是否进行覆盖;默认进行覆盖
- *
- * @return copy成功:true;copy失败:false
- */
- bool copyDirectoryFiles(const QDir &fromDir,
- const QDir &toDir,
- bool coverFileIfExist = true);
- /**
- * 删除目录
- *
- * @param dirName 目录名称
- *
- * @return 删除目录成功:true;删除目录失败:false
- */
- bool removeDirectory(QString dirName);
- /**
- * 创建目录
- *
- * @param target 目录的路径
- * 说明:当target为空则不做任何操作,直接返回;
- * 当传递的参数为aa/bb/则会在当前目录上创建aa/bb/目录(最后的‘/’不能省掉)
- * 当传递的参数为aa/bb/cc/dd.txt则会在当前的目录下创建aa/bb/cc目录
- *
- * 注:此方法主要是被download(QUrl url, QString target)
- * 调用以创建相关的目录结构
- */
- void createDirectory(QString target);
- };
- #endif
HttpDownload的实现文件(HttpDownload.cpp)
- /******************************************************************************
- *
- * 文件名: HttpDownload.cpp
- *
- * 文件摘要: HttpDownload.h的实现类
- *
- * 作者:程晓鹏
- *
- * 文件创建时间: 2011/09/05 11:28:59
- *
- *******************************************************************************/
- #include "HttpDownload.h"
- HttpDownload::HttpDownload(QObject * parent)
- {
- http = new QHttp(this);
- httpDown = new QHttp(this);
- connect(httpDown, SIGNAL(requestFinished(int,bool)),
- this, SLOT(httpRequestFinish(int,bool)));
- connect(httpDown,SIGNAL(readyRead(QHttpResponseHeader)),
- this, SLOT(httpDownloadReadReady(QHttpResponseHeader)));
- connect(httpDown, SIGNAL(dataReadProgress(int,int)),
- this, SIGNAL(downloadProgress(int,int)));
- connect(http, SIGNAL(readyRead(QHttpResponseHeader)),
- this, SLOT(httpReadReady(QHttpResponseHeader)));
- strTmpDownDir = ".tmp_down/"; //定义下载文件的临时目录
- strBakDir = ".tmp_bak/"; //定义备份文件所在的临时目录
- }
- void HttpDownload::setDownloadTempFolder(QString folderName)
- {
- if(folderName != ""){
- strTmpDownDir = getFolderName(folderName);
- }
- }
- QString HttpDownload::getFolderName(QString folderName)
- {
- QString strResult = "";
- if(folderName != ""){
- strResult = folderName;
- if(!strResult.endsWith("/")){
- strResult = strResult.append("/");
- }
- }
- return strResult;
- }
- QString HttpDownload::getFolderPath(QString filePath)
- {
- QString strResult = "";
- if(filePath != ""){
- QFileInfo fileInfo (filePath);
- strResult = fileInfo.path();
- }
- return strResult;
- }
- void HttpDownload::setBackupTempFolder(QString folderName)
- {
- if(folderName != ""){
- strBakDir = getFolderName(folderName);
- }
- }
- void HttpDownload::backupFile(QString filePath)
- {
- QString strDestDir = strBakDir + filePath;
- createDirectory(strDestDir); /**< 创建备份文件所在的目录(包含自身的目录结构) */
- QFileInfo sourceFile(filePath);
- QFile::copy(filePath, strDestDir); /**< 进行文件copy */
- }
- void HttpDownload::restoreBackupFiles()
- {
- copyDirectoryFiles(QDir(strBakDir), QDir::current(), true);
- removeDirectory(strBakDir);
- }
- void HttpDownload::deleteDownloadTempFiles()
- {
- removeDirectory(strTmpDownDir);
- }
- void HttpDownload::download(QUrl url, QString target)
- {
- QString strDownFolder = strTmpDownDir + target;
- createDirectory(strDownFolder);
- initHttp(httpDown, url, false);
- QString strfileName = getFileName(url);
- if(strfileName.isEmpty()){
- strfileName = "index.html";
- }
- //将文件下载到临时目录中(在文件名的前面添加临时目录的名称)
- strfileName = getFolderName(getFolderPath(strDownFolder)).append(strfileName);
- file = new QFile();
- file->setFileName(strfileName);
- if(!file->open(QIODevice::WriteOnly)){
- deleteFile(file);
- return;
- }
- QByteArray path = QUrl::toPercentEncoding(url.path(), "!$&'()*+,;=:@/");
- httpid = httpDown->get(path,file);
- }
- void HttpDownload::createDirectory(QString target){
- if(target == "")
- return;
- int idx = target.lastIndexOf("/");
- QString strDir = target.mid(0,idx);
- QDir dir;
- dir.mkpath(strDir);
- }
- void HttpDownload::initHttp(QHttp *myhttp, QUrl url, bool isNew)
- {
- if(isNew){
- myhttp = new QHttp(this);
- }
- QHttp::ConnectionMode mode = url.scheme().toLower() == "https"
- ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp;
- myhttp->setHost(url.host(), mode, url.port() == -1 ? 80 : url.port());
- }
- void HttpDownload::beginHttpRequest(QUrl url, QString requestData)
- {
- initHttp(http, url, false);
- header = QHttpRequestHeader("POST",url.toString());
- header.setContentType("application/x-www-form-urlencoded");
- http->request(header,requestData.toUtf8());
- }
- void HttpDownload::finishDownload()
- {
- /// 将临时目录中的文件,copy到当前目录中
- copyDirectoryFiles(QDir(strTmpDownDir), QDir::current(), true);
- removeDirectory(strTmpDownDir);
- removeDirectory(strBakDir);
- }
- void HttpDownload::httpRequestFinish(int requestID, bool error)
- {
- if(error){
- //removeDirectory(strTmpDownDir);
- //removeDirectory(strBakDir);
-
- qDebug() << "error" << endl;
- }
- else{
- file->flush();
- file->close();
- emit downFinish();
- }
- if(httpid != requestID){
- return;
- }
- file->flush();
- file->close();
- }
- void HttpDownload::httpDownloadReadReady(const QHttpResponseHeader &resp)
- {
- file->write(httpDown->readAll());
- }
- void HttpDownload::httpReadReady(const QHttpResponseHeader &resp)
- {
- QString strResult = QString(http->readAll());
- emit getHttpResponse(strResult);
- }
- QString HttpDownload::getFileName(QString path)
- {
- QFileInfo fileInfo (path);
- QString strFileName = fileInfo.fileName();
- return strFileName;
- }
- QString HttpDownload::getFileName(QUrl url)
- {
- return getFileName(url.path());
- }
- void HttpDownload::deleteFile(QFile *myfile)
- {
- myfile->close();
- delete myfile;
- myfile = NULL;
- }
- void HttpDownload::deleteHttp(QHttp *myhttp)
- {
- myhttp->close();
- delete myhttp;
- myhttp = NULL;
- }
- bool HttpDownload::copyDirectoryFiles(const QDir &fromDir,
- const QDir &toDir,
- bool coverFileIfExist)
- {
- QDir sourceDir = fromDir;
- QDir targetDir = toDir;
- if(!targetDir.exists()){ /**< 如果目标目录不存在,则进行创建 */
- if(!targetDir.mkdir(toDir.absolutePath()))
- return false;
- }
-
- QFileInfoList fileInfoList = sourceDir.entryInfoList();
- foreach(QFileInfo fileInfo, fileInfoList){
- if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
- continue;
- if(fileInfo.isDir()){ /**< 当为目录时,递归的进行copy */
- if(!copyDirectoryFiles(fileInfo.filePath(),
- targetDir.filePath(fileInfo.fileName()),
- coverFileIfExist))
- return false;
- }
- else{ /**< 当允许覆盖操作时,将旧文件进行删除操作 */
- if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
- targetDir.remove(fileInfo.fileName());
- }
- /// 进行文件copy
- if(!QFile::copy(fileInfo.filePath(),
- targetDir.filePath(fileInfo.fileName()))){
- return false;
- }
- }
- }
- return true;
- }
- bool HttpDownload::removeDirectory(QString dirName)
- {
- QDir dir(dirName);
- QString tmpdir = "";
- if(!dir.exists()){
- return false;
- }
- QFileInfoList fileInfoList = dir.entryInfoList();
- foreach(QFileInfo fileInfo, fileInfoList){
- if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
- continue;
-
- if(fileInfo.isDir()){
- tmpdir = dirName + ("/") + fileInfo.fileName();
- removeDirectory(tmpdir);
- dir.rmdir(fileInfo.fileName()); /**< 移除子目录 */
- }
- else if(fileInfo.isFile()){
- QFile tmpFile(fileInfo.fileName());
- dir.remove(tmpFile.fileName()); /**< 删除临时文件 */
- }
- else{
- ;
- }
- }
- dir.cdUp(); //返回上级目录,因为只有返回上级目录,才可以删除这个目录
- if(dir.exists(dirName)){
- if(!dir.rmdir(dirName))
- return false;
- }
- return true;
- }
- HttpDownload::~HttpDownload()
- {
- if(file){
- deleteFile(file);
- }
- if(http){
- deleteHttp(http);
- }
- if(httpDown){
- deleteHttp(httpDown);
- }
- }
当然还有该项目的.pro文件,在该文件中指定编写为库文件,代码如下:
- TARGET = HttpDownload
- TEMPLATE = lib
- QT += network
- DEPENDPATH += .
- INCLUDEPATH += .
- HEADERS += HttpDownload.h
- SOURCES += HttpDownload.cpp
- #destination-director location
- DESTDIR= ../lib
- # temp-director location
- OBJECTS_DIR = ../.tmp
- MOC_DIR = ../.moc
- UI_DIR += ../.tmp
具体的如何使用,请参看附件中代码。
阅读(8434) | 评论(0) | 转发(2) |