Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2538615
  • 博文数量: 308
  • 博客积分: 5547
  • 博客等级: 大校
  • 技术积分: 3782
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-24 09:47
个人简介

hello world.

文章分类

全部博文(308)

分类: C/C++

2011-09-18 10:42:38

    我们不免有要通过Http下载一些文件的需求,开始的时候,也是通过在一个文件中编写很多的代码,但是当我们在其他的地方使用的时候,我们有时候又要重新编写一次。很是麻烦。我在想是否可以编写一个类库来实现通过Http下载文件的功能。经过一段时间的努力,终于实现了。下载的原理是,给一个下载的绝对路径,和要下载的目标地址,这样可以下载到临时目录中,当下载完成是,移动下载到临时目录中的文件到当前目录中(根据下载的文件,可以本地已经存在的文件进行备份)。核心代码如下:
  1. /******************************************************************************
  2.  *
  3.  * 文件名: HttpDownload.h
  4.  *
  5.  * 文件摘要: Http下载类
  6.  *
  7.  * 作者:程晓鹏
  8.  *
  9.  * 文件创建时间: 2011/09/05 11:28:35
  10.  *
  11.  *******************************************************************************/

  12. #ifndef HTTPDOWNLOAD_H
  13. #define HTTPDOWNLOAD_H

  14. #include <QFile>
  15. #include <QHttp>
  16. #include <QUrl>
  17. #include <QString>
  18. #include <QtNetwork>
  19. #include <QHttpResponseHeader>
  20. #include <QDebug>
  21. #include <QDir>
  22. #include <QMessageBox>


  23. /**
  24.  * Http下载类
  25.  *
  26.  */
  27. class HttpDownload : public QObject{
  28.   
  29.   Q_OBJECT
  30.   public:
  31.   
  32.   /**
  33.    * 构造函数
  34.    *
  35.    * @param parent 父窗体ID
  36.    *
  37.    */
  38.   HttpDownload(QObject* parent=0);

  39.   /**
  40.    * 进行下载
  41.    *
  42.    * @param url 下载的URL地址
  43.    * @param target 下载目录,或者文件(默认为空,则下载在临时目录.tmp_down目录下)
  44.    *
  45.    * 说明:当该下载操作成功,仅将需要下载的文件下载到
  46.    * 当前目录下的 .tmp_down临时目录中
  47.    * (如果想更改临时目录的名称,需要在调用此方法前调用
  48.    * setDownloadTempFloder(QString)方法,更改临时目录名称)
  49.    *
  50.    * 如果您需要将文件从临时目录中移动到当前目录中,
  51.    * 并删除该临时目录,需要调用finishDownload方法。
  52.    *
  53.    * target参数,为下载的时文件所存放的路径
  54.    * 如target为/update/down/ 则下载的文件将会在
  55.    * 当前目录下创建update/down目录结构,(注意参数中的最后一定要带上‘/’)
  56.    * 将url路径指定的文件保存在此目录下。
  57.    *
  58.    * 另外当target为 /update/down/test.jpg,
  59.    * 则系同样会创建/update/down目录
  60.    * 将url路径指定的文件保存在此目录下
  61.    */
  62.   void download(QUrl url, QString target = "");

  63.   /**
  64.    * 进行HTTP请求
  65.    *
  66.    * @param url 进行HTTP请求的URL
  67.    * @requestData 请求的数据
  68.    *
  69.    * 说明:当调用该方法时,如果该方法执行成功,将会
  70.    * 发出 getHttpResponse(QString response)信号
  71.    */
  72.   void beginHttpRequest(QUrl url, QString requestData = "");

  73.   /**
  74.    * 完成下载的文件
  75.    *
  76.    * 说明:将下载的文件进行替换操作 & 删除下载的文件
  77.    *
  78.    */
  79.   void finishDownload();

  80.   /**
  81.    * 设置下载临时目录的名称
  82.    *
  83.    * @param folderName 目录的名称
  84.    *
  85.    * 备注:建议folderName为一级目录名称 如:tmp
  86.    * 注意:不要和setBackupTempFolder设置为同一个名称
  87.    */
  88.   void setDownloadTempFolder(QString folderName = ".tmp_down");

  89.   /**
  90.    * 设置备份文件所在的目录
  91.    *
  92.    * @param folderName 目录的名称
  93.    *
  94.    * 备注:建议folderName为一级目录名称如:bak
  95.    * 注意:不要和setDownloadTempFolder设置为同一个名称
  96.    */
  97.   void setBackupTempFolder(QString folderName = ".tmp_bak");

  98.   /**
  99.    * 备份文件
  100.    *
  101.    * @param filePath 文件的相对路径
  102.    *
  103.    * 说明:如果路径中存在目录,则自动创建相应的目录
  104.    * 备注:此方法只能针对一个文件的相对路径,而不能针对多个文件
  105.    */
  106.   void backupFile(QString filePath);

  107.   /**
  108.    * 还原已经备份的文件
  109.    *
  110.    * 说明:还原备份的文件,删除备份文件的目录
  111.    */
  112.   void restoreBackupFiles();

  113.   /**
  114.    * 删除下载的临时文件
  115.    *
  116.    */
  117.   void deleteDownloadTempFiles();

  118.   /**
  119.    * 获取文件名
  120.    *
  121.    * @param path 文件的路径
  122.    *
  123.    * @return 文件名
  124.    */
  125.   QString getFileName(QString path);
  126.   
  127.   /**
  128.    * 析构函数
  129.    *
  130.    */
  131.   ~HttpDownload();

  132. signals:

  133.   /**
  134.    * 下载文件的进度
  135.    *
  136.    * @param done 当前的下载量
  137.    * @param total 下载的总量
  138.    */
  139.   void downloadProgress(int done, int total);

  140.   /**
  141.    * 获取HTTP请求的响应字符串
  142.    *
  143.    * @response HTTP响应字符串
  144.    */
  145.   void getHttpResponse(QString response);

  146.   /**
  147.    * 下载文件完成的信号
  148.    *
  149.    */
  150.   void downFinish();

  151.  private slots:

  152.   /**
  153.    * 当HTTP请求完成时
  154.    *
  155.    * @param requestID 请求的ID
  156.    * @param error 返回请求是否成功
  157.    */
  158.   void httpRequestFinish(int requestID, bool error);

  159.   /**
  160.    * 当HTTP请求开始时
  161.    *
  162.    * @param resp HTTP响应头对象
  163.    */
  164.   void httpReadReady(const QHttpResponseHeader &resp);

  165.   /**
  166.    * 当HTTP请求开始下载文件时
  167.    *
  168.    * @param resp HTTP响应头对象
  169.    */
  170.   void httpDownloadReadReady(const QHttpResponseHeader &resp);

  171.  private:
  172.   QHttp *http;
  173.   QHttp *httpDown;
  174.   QFile *file;
  175.   QHttpRequestHeader header;
  176.   int httpid;
  177.   QString strTmpDownDir; //定义下载文件的临时目录
  178.   QString strBakDir; //定义备份文件所在的临时目录

  179.   /**
  180.    * 根据目录名称,获取带有'/'结束的目录名称
  181.    *
  182.    * @param folderName 目录名称
  183.    *
  184.    * @return 带有'/'结束的目录名称
  185.    */
  186.   QString getFolderName(QString folderName);


  187.   QString getFolderPath(QString filePath);

  188.   /**
  189.    * 删除文件指针
  190.    *
  191.    * @param myfile 文件指针
  192.    */
  193.   void deleteFile(QFile *myfile);

  194.   /**
  195.    * 删除Http指针
  196.    *
  197.    * @param myhttp HTTP请求指针
  198.    */
  199.   void deleteHttp(QHttp *myhttp);

  200.   /**
  201.    * 初始化Http对象
  202.    *
  203.    * @param myhttp http指针
  204.    * @url 连接的URL
  205.    * @isNew 是否实例化myhttp
  206.    */
  207.   void initHttp(QHttp *myhttp, QUrl url, bool isNew);

  208.   /**
  209.    * 获取文件名
  210.    *
  211.    * @param url Http的Url
  212.    *
  213.    * @return 文件名
  214.    */
  215.   QString getFileName(QUrl url);

  216.   /**
  217.    * copy一个目录中的文件到另外一个目录
  218.    *
  219.    * @param fromDir 源目录
  220.    * @param toDir 目标目录
  221.    * @param coverFileIfExist 当目标目录中存在同名文件,是否进行覆盖;默认进行覆盖
  222.    *
  223.    * @return copy成功:true;copy失败:false
  224.    */
  225.   bool copyDirectoryFiles(const QDir &fromDir,
  226.              const QDir &toDir,
  227.              bool coverFileIfExist = true);

  228.   /**
  229.    * 删除目录
  230.    *
  231.    * @param dirName 目录名称
  232.    *
  233.    * @return 删除目录成功:true;删除目录失败:false
  234.    */
  235.   bool removeDirectory(QString dirName);

  236.   /**
  237.    * 创建目录
  238.    *
  239.    * @param target 目录的路径
  240.    * 说明:当target为空则不做任何操作,直接返回;
  241.    * 当传递的参数为aa/bb/则会在当前目录上创建aa/bb/目录(最后的‘/’不能省掉)
  242.    * 当传递的参数为aa/bb/cc/dd.txt则会在当前的目录下创建aa/bb/cc目录
  243.    *
  244.    * 注:此方法主要是被download(QUrl url, QString target)
  245.    * 调用以创建相关的目录结构
  246.    */
  247.   void createDirectory(QString target);
  248. };

  249. #endif
HttpDownload的实现文件(HttpDownload.cpp)
  1. /******************************************************************************
  2.  *
  3.  * 文件名: HttpDownload.cpp
  4.  *
  5.  * 文件摘要: HttpDownload.h的实现类
  6.  *
  7.  * 作者:程晓鹏
  8.  *
  9.  * 文件创建时间: 2011/09/05 11:28:59
  10.  *
  11.  *******************************************************************************/

  12. #include "HttpDownload.h"

  13. HttpDownload::HttpDownload(QObject * parent)
  14. {
  15.   http = new QHttp(this);
  16.   httpDown = new QHttp(this);
  17.   connect(httpDown, SIGNAL(requestFinished(int,bool)),
  18.      this, SLOT(httpRequestFinish(int,bool)));
  19.   connect(httpDown,SIGNAL(readyRead(QHttpResponseHeader)),
  20.      this, SLOT(httpDownloadReadReady(QHttpResponseHeader)));
  21.   connect(httpDown, SIGNAL(dataReadProgress(int,int)),
  22.      this, SIGNAL(downloadProgress(int,int)));
  23.   connect(http, SIGNAL(readyRead(QHttpResponseHeader)),
  24.      this, SLOT(httpReadReady(QHttpResponseHeader)));

  25.   strTmpDownDir = ".tmp_down/"; //定义下载文件的临时目录
  26.   strBakDir = ".tmp_bak/"; //定义备份文件所在的临时目录
  27. }

  28. void HttpDownload::setDownloadTempFolder(QString folderName)
  29. {
  30.   if(folderName != ""){
  31.     strTmpDownDir = getFolderName(folderName);
  32.   }
  33. }

  34. QString HttpDownload::getFolderName(QString folderName)
  35. {
  36.   QString strResult = "";
  37.   if(folderName != ""){
  38.     strResult = folderName;
  39.     if(!strResult.endsWith("/")){
  40.       strResult = strResult.append("/");
  41.     }
  42.   }

  43.   return strResult;
  44. }

  45. QString HttpDownload::getFolderPath(QString filePath)
  46. {
  47.     QString strResult = "";
  48.     if(filePath != ""){
  49.         QFileInfo fileInfo (filePath);
  50.         strResult = fileInfo.path();
  51.     }

  52.     return strResult;
  53. }

  54. void HttpDownload::setBackupTempFolder(QString folderName)
  55. {
  56.   if(folderName != ""){
  57.     strBakDir = getFolderName(folderName);
  58.   }
  59. }

  60. void HttpDownload::backupFile(QString filePath)
  61. {
  62.   QString strDestDir = strBakDir + filePath;
  63.   createDirectory(strDestDir);    /**< 创建备份文件所在的目录(包含自身的目录结构) */
  64.   QFileInfo sourceFile(filePath);
  65.   QFile::copy(filePath, strDestDir); /**< 进行文件copy */
  66. }

  67. void HttpDownload::restoreBackupFiles()
  68. {
  69.   copyDirectoryFiles(QDir(strBakDir), QDir::current(), true);
  70.   removeDirectory(strBakDir);
  71. }

  72. void HttpDownload::deleteDownloadTempFiles()
  73. {
  74.   removeDirectory(strTmpDownDir);
  75. }

  76. void HttpDownload::download(QUrl url, QString target)
  77. {
  78.   QString strDownFolder = strTmpDownDir + target;
  79.   createDirectory(strDownFolder);
  80.   initHttp(httpDown, url, false);
  81.   QString strfileName = getFileName(url);
  82.   if(strfileName.isEmpty()){
  83.     strfileName = "index.html";
  84.   }

  85.   //将文件下载到临时目录中(在文件名的前面添加临时目录的名称)
  86.   strfileName = getFolderName(getFolderPath(strDownFolder)).append(strfileName);
  87.   file = new QFile();
  88.   file->setFileName(strfileName);
  89.   if(!file->open(QIODevice::WriteOnly)){
  90.     deleteFile(file);
  91.     return;
  92.   }
  93.   QByteArray path = QUrl::toPercentEncoding(url.path(), "!$&'()*+,;=:@/");
  94.   httpid = httpDown->get(path,file);
  95. }

  96. void HttpDownload::createDirectory(QString target){
  97.   if(target == "")
  98.     return;

  99.   int idx = target.lastIndexOf("/");
  100.   QString strDir = target.mid(0,idx);
  101.   QDir dir;
  102.   dir.mkpath(strDir);
  103. }

  104. void HttpDownload::initHttp(QHttp *myhttp, QUrl url, bool isNew)
  105. {
  106.   if(isNew){
  107.     myhttp = new QHttp(this);
  108.   }
  109.   QHttp::ConnectionMode mode = url.scheme().toLower() == "https"
  110.     ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp;

  111.   myhttp->setHost(url.host(), mode, url.port() == -1 ? 80 : url.port());
  112. }

  113. void HttpDownload::beginHttpRequest(QUrl url, QString requestData)
  114. {
  115.   initHttp(http, url, false);
  116.   header = QHttpRequestHeader("POST",url.toString());
  117.   header.setContentType("application/x-www-form-urlencoded");
  118.   http->request(header,requestData.toUtf8());
  119. }

  120. void HttpDownload::finishDownload()
  121. {
  122.   /// 将临时目录中的文件,copy到当前目录中
  123.   copyDirectoryFiles(QDir(strTmpDownDir), QDir::current(), true);
  124.   removeDirectory(strTmpDownDir);
  125.   removeDirectory(strBakDir);
  126. }

  127. void HttpDownload::httpRequestFinish(int requestID, bool error)
  128. {

  129.   if(error){
  130.     //removeDirectory(strTmpDownDir);
  131.     //removeDirectory(strBakDir);
  132.     
  133.     qDebug() << "error" << endl;
  134.   }
  135.   else{
  136.       file->flush();
  137.       file->close();
  138.       emit downFinish();
  139.   }

  140.   if(httpid != requestID){
  141.     return;
  142.   }

  143.   file->flush();
  144.   file->close();
  145. }

  146. void HttpDownload::httpDownloadReadReady(const QHttpResponseHeader &resp)
  147. {
  148.   file->write(httpDown->readAll());
  149. }

  150. void HttpDownload::httpReadReady(const QHttpResponseHeader &resp)
  151. {
  152.   QString strResult = QString(http->readAll());
  153.   emit getHttpResponse(strResult);
  154. }

  155. QString HttpDownload::getFileName(QString path)
  156. {
  157.   QFileInfo fileInfo (path);
  158.   QString strFileName = fileInfo.fileName();
  159.   return strFileName;
  160. }

  161. QString HttpDownload::getFileName(QUrl url)
  162. {
  163.   return getFileName(url.path());
  164. }

  165. void HttpDownload::deleteFile(QFile *myfile)
  166. {
  167.   myfile->close();
  168.   delete myfile;
  169.   myfile = NULL;
  170. }

  171. void HttpDownload::deleteHttp(QHttp *myhttp)
  172. {
  173.   myhttp->close();
  174.   delete myhttp;
  175.   myhttp = NULL;
  176. }

  177. bool HttpDownload::copyDirectoryFiles(const QDir &fromDir,
  178.                  const QDir &toDir,
  179.                  bool coverFileIfExist)
  180. {
  181.   QDir sourceDir = fromDir;
  182.   QDir targetDir = toDir;
  183.   if(!targetDir.exists()){    /**< 如果目标目录不存在,则进行创建 */
  184.     if(!targetDir.mkdir(toDir.absolutePath()))
  185.       return false;
  186.   }
  187.   
  188.   QFileInfoList fileInfoList = sourceDir.entryInfoList();
  189.   foreach(QFileInfo fileInfo, fileInfoList){
  190.     if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
  191.       continue;

  192.     if(fileInfo.isDir()){    /**< 当为目录时,递归的进行copy */
  193.       if(!copyDirectoryFiles(fileInfo.filePath(),
  194.              targetDir.filePath(fileInfo.fileName()),
  195.              coverFileIfExist))
  196.     return false;
  197.     }
  198.     else{            /**< 当允许覆盖操作时,将旧文件进行删除操作 */
  199.       if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
  200.     targetDir.remove(fileInfo.fileName());
  201.       }

  202.       /// 进行文件copy
  203.       if(!QFile::copy(fileInfo.filePath(),
  204.          targetDir.filePath(fileInfo.fileName()))){
  205.     return false;
  206.       }
  207.     }
  208.   }
  209.   return true;
  210. }

  211. bool HttpDownload::removeDirectory(QString dirName)
  212. {
  213.   QDir dir(dirName);
  214.   QString tmpdir = "";
  215.   if(!dir.exists()){
  216.     return false;
  217.   }

  218.   QFileInfoList fileInfoList = dir.entryInfoList();
  219.   foreach(QFileInfo fileInfo, fileInfoList){
  220.     if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
  221.       continue;
  222.     
  223.     if(fileInfo.isDir()){
  224.       tmpdir = dirName + ("/") + fileInfo.fileName();
  225.       removeDirectory(tmpdir);
  226.       dir.rmdir(fileInfo.fileName()); /**< 移除子目录 */
  227.     }
  228.     else if(fileInfo.isFile()){
  229.       QFile tmpFile(fileInfo.fileName());
  230.       dir.remove(tmpFile.fileName()); /**< 删除临时文件 */
  231.     }
  232.     else{
  233.       ;
  234.     }
  235.   }

  236.   dir.cdUp(); //返回上级目录,因为只有返回上级目录,才可以删除这个目录
  237.   if(dir.exists(dirName)){
  238.     if(!dir.rmdir(dirName))
  239.       return false;
  240.   }
  241.   return true;
  242. }

  243. HttpDownload::~HttpDownload()
  244. {
  245.   if(file){
  246.     deleteFile(file);
  247.   }

  248.   if(http){
  249.     deleteHttp(http);
  250.   }

  251.   if(httpDown){
  252.     deleteHttp(httpDown);
  253.   }

  254. }
当然还有该项目的.pro文件,在该文件中指定编写为库文件,代码如下:
  1. TARGET = HttpDownload
  2. TEMPLATE = lib
  3. QT += network
  4. DEPENDPATH += .
  5. INCLUDEPATH += .
  6. HEADERS += HttpDownload.h
  7. SOURCES += HttpDownload.cpp
  8. #destination-director location
  9. DESTDIR= ../lib
  10. # temp-director location
  11. OBJECTS_DIR = ../.tmp
  12. MOC_DIR = ../.moc
  13. UI_DIR += ../.tmp
具体的如何使用,请参看附件中代码。
阅读(8434) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~