码迷,mamicode.com
首页 > Web开发 > 详细

libCURL在Qt中的使用

时间:2014-10-14 16:12:58      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   使用   ar   for   

  最近业余时间在搞Qt,其中的一个功能是实现FTP的上传下载。

  之前版本的Qt提供了一个FTP操作的类,但是5.x(4.x?)之后因为性能问题就弃用了。貌似CSDN上有人发帖问过这个问题,记得应该是put多大的文件时导致占用内存过大。现在Qt的官方手册推荐使用QNetworkAccessManager用于TCP/IP以及FTP的传输。说实话这玩意对于FTP的兼容并不好。于是想到了CURL。

  网上关于CURL和libCURL的文章很多,但是用于FTP操作的文章大多数停留于试验性的代码。别的不说,忽略了一个比较重要的问题就是FTP的传输模式。

  FTP有两种传输模式,ASCII和Binary,即TYPE A 和TYPE I。大家的文章里面都没有提到这个事情。我用libCURL主要是传输文本文件,所以这个问题一下就浮现出来了。

  libCURL的下载什么的就不说了,到官网上找windows的包就可以,记得下载develop版本。

  在QT里面使用动态库,首先要做的肯定是修改pro文件。

 

1 LIBS    += C:\your-curl-lib-location\curl-7.34.0-devel-mingw32\lib\libcurldll.a
2 
3 INCLUDEPATH += C:\your-curl-lib-location\curl-7.34.0-devel-mingw32\include

  首先指定静态库位置,接着指定include路径。这个没什么好说的。然后把curl路径下的bin目录中的dll拷贝到debug文件夹。否则run的时候会“莫名其妙”的停止。

  这里使用的是CURL的easy借口(貌似网上的文章都是使用的这个)。

  先来看下下载代码。

 1     CURLcode ret;
 2     curl_global_init(CURL_GLOBAL_ALL);
 3     CURL* curl = curl_easy_init(); 
 4 
 5     curl_easy_setopt(curl,CURLOPT_URL,remoteFile.toLatin1().data()); 
 6     curl_easy_setopt(curl,CURLOPT_USERPWD,"username:password"); 
 7     ret = curl_easy_setopt(curl,CURLOPT_WRITEDATA,localFile); 
 8     ret = curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curlWriteFunction);
 9 
10     curl_easy_setopt(curl,CURLOPT_TRANSFERTEXT,1);
11 
12     curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
13     ret = curl_easy_perform(curl);
14 
15     curl_easy_cleanup(curl);
16     curl_global_cleanup();

  解释几点。

    1)  声明CURLcode,获取curl接口的返回值。

    2)  使用 curl_global_init对CURL进行初始化。传递CURL_GLOBAL_ALL进去表明对所有平台进行初始化,这个是最保险的,也保证了代码的可移植性。

    3)  curl_easy_setopt函数对curl的选项进行设定。

         该函数的第一个参数为curl指针,第二个为CURL选项名称(其实就是个整数),第三个为实际选项的值,可以是字符串、指针,函数指针等,根据不同的选项有不同的值。

          CURLOPT_URL:  设定需要上传/下载的文件URL。

          CURLOPT_USERPWD:设定登录服务器的账号密码,格式为user:passwd。

          CURLOPT_WRITEDATA:传递DATA的指针。引用一句被用烂的话,“CURL对该指针不做任何处理,只做传递作用。”。这个指针有什么用,我们一会儿再看。

          CURLOPT_WRITEFUNCTION:设定写文件的函数。当curl从服务器获取数据之后,便会调用这个函数做写入处理。函数原型如下:

            size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);

            看见最后一个参数了米有?这个参数就是CURLOPT_WRITEDATA中指定的指针。也就是,如果你想指定几个参数贯穿CURL“获取-写入"这个过程,就把他们的指针通过CURLOPT_WRITEDATA传给CURL。这里我给了个QFile指针进去。

            需要说明的一点是,如果在C++中只用CURL,这个函数在类中应当被声明为static的。

        CURLOPT_TRANSFERTEXT: 指定CURL的FTP传输模式。后面的值为1,则为ASCII,0位二进制传输。如果使用了错误的传输模式,在下载的过程中,服务器可能给你一个553。最开始这个错误让我很莫名其妙。因为我使用了CURLOPT_PREQUOTE去追加了一个TYPE A的命令给CURL。理论上应该是可行的,但实际上文件传输总是到一半就被服务器关闭链接。猜测这个可能与CURL的多线程有关?仅仅做猜测了。

        CURLOPT_VERBOSE 设定调试级别。

        在libCURL的网站上,有一个链接专门解释这些宏。

        

1 http://curl.haxx.se/libcurl/c/curl_easy_setopt.html

 

 

    4)   curl_easy_perform 执行curl动作。默认为下载。

 

  对CURL设置结束后,就可以编写之前指定的写入函数了。

     

1 int FTPThread::curlWriteFunction(void *buffer, size_t size, size_t nmemb, void *stream){
2     QFile* file = static_cast<QFile*>(stream);
3     if(!file->isOpen()){
4         file->open(QFile::ReadWrite | QIODevice::Text);
5     }
6     return file->write((char*)buffer,nmemb);
7 
8 }

  在QT中,这个函数是很容易被实现的。只要确保返回值为实际的写入字节就可以,因为CURL会检查返回值,如果与nmemb不相等的话,会报错。

 

  上传的代码与下载很类似,直接上代码了。

 

 1 CURLcode FTPThread::CURLUpload(){
 2     CURLcode ret;
 3     curl_global_init(CURL_GLOBAL_ALL);
 4     CURL* curl = curl_easy_init();
 5     QFile* localFile = new QFile("FTPCache/"+fileName);
 6     qDebug()<<localFile->fileName()<<endl;
 7     QString remoteFile = "ftp://your.ftp.server/"+fileName;
 8 
 9     if(!localFile->open(QFile::ReadWrite | QIODevice::Text)){
10         qDebug()<<"open file fail"<<endl;
11         return CURLE_READ_ERROR;
12     }
13 
14     curl_easy_setopt(curl,CURLOPT_URL,remoteFile.toLatin1().data());
15     curl_easy_setopt(curl,CURLOPT_USERPWD,"username:password");
16 
17     curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
18     curl_easy_setopt(curl,CURLOPT_FTP_CREATE_MISSING_DIRS,CURLFTP_CREATE_DIR);
19     ret = curl_easy_setopt(curl,CURLOPT_READDATA,localFile);
20     curl_easy_setopt(curl,CURLOPT_INFILESIZE_LARGE,localFile->size());
21     ret = curl_easy_setopt(curl,CURLOPT_READFUNCTION,curlReadFunction);
22 
23     //Timeout
24     curl_easy_setopt(curl,CURLOPT_FTP_RESPONSE_TIMEOUT,60000);
25 
26 
27     //Set transfer mode to ASCII
28     curl_easy_setopt(curl,CURLOPT_TRANSFERTEXT,1);
29     curl_easy_setopt(curl,CURLOPT_BUFFERSIZE,200);
30 
31 
32     curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
33     ret = curl_easy_perform(curl);
34     if(ret!=CURLE_OK)
35             qDebug()<<"perform fail"<<endl;
36 
37     curl_easy_cleanup(curl);
38     curl_global_cleanup();
39     localFile->close();
40     return ret;
41 }

  只需说明一点,curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); 指定了CURL的动作为上传。

  读取文件的函数原型如下:

 

1 size_t read_callback(char *buffer, size_t size, size_t nitems, void *instream);

 

  实现如下:

1 int FTPThread::curlReadFunction(void *buffer, size_t size, size_t nmemb, void *stream){
2     QFile* file = static_cast<QFile*>(stream);
3     return file->read((char*)buffer,size*nmemb);
4 }

 

  全文完。

 

libCURL在Qt中的使用

标签:style   blog   http   color   io   os   使用   ar   for   

原文地址:http://www.cnblogs.com/widekuan/p/4024186.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!