从ftp服务器下载文件,并要显示下载进度,最好支持断点续传

daredjever 2011-09-08 10:59:29
大家好:
现在需要去FTP服务器下载一个文件,本地程序检测需要下载的是就去下载,本地要显示下载进度,最好支持断点续传功能,哪位做过指点一下?
看网上有些是用MFC做的,能不能不用MFC的类?
...全文
390 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
limang89 2011-09-08
  • 打赏
  • 举报
回复

//读取内容
UINT nReadCount=0;
TCHAR szDownBuffer[4096];
m_pHttpFile=(CHttpFile *)m_InternetSession.OpenURL(m_pDownLoadRequest->szDownLoadUrl,1,INTERNET_FLAG_TRANSFER_ASCII|INTERNET_FLAG_DONT_CACHE);
nReadCount=m_pHttpFile->Read(szDownBuffer,sizeof(szDownBuffer));
if (nReadCount<sizeof(szErrorHtml1)) throw 0;
if (nReadCount<sizeof(szErrorHtml2)) throw 0;
if (memcmp(szErrorHtml1,szDownBuffer,lstrlen(szErrorHtml1))==0) throw 0;
if (memcmp(szErrorHtml2,szDownBuffer,lstrlen(szErrorHtml2))==0) throw 0;

//读取大小
ASSERT(m_pHttpFile!=NULL);
BOOL bSuccess=m_pHttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER,m_dwTotalFileSize);
if (bSuccess==FALSE) throw enDownLoadResult_InternetReadError;

//本地文件
_snprintf(m_szTempFile,sizeof(m_szTempFile),TEXT("%s\\%s.DTM"),m_pDownLoadRequest->szLocalPath,m_pDownLoadRequest->szFileName);
if (m_LocalFile.Open(m_szTempFile,CFile::modeReadWrite|CFile::modeCreate)==FALSE) throw enDownLoadResult_CreateFileFails;

//写入文件
m_LocalFile.Write(szDownBuffer,nReadCount);

//设置变量
m_ThreadLock.Lock();
m_DownLoadStatus=enDownLoadStatus_DownLoadIng;
m_dwDownLoadSize+=nReadCount;
m_ThreadLock.UnLock();

//设置变量
m_bPreparative=true;
zhanshen2891 2011-09-08
  • 打赏
  • 举报
回复
用wininet API也可以,MSDN上有例子,记得是有例子
bdmh 2011-09-08
  • 打赏
  • 举报
回复
服务器和本地都有一个文件,记录每个文件的版本和大小,每次启动时,从服务器上下载这个文件和本地文件比对,列出要下载的文件,c#的ftp下载可以获取下载大小,这样就可以对比文件中的大小进行进度显示,还可以记录已经下载多少,这样可以实现续传
luciferisnotsatan 2011-09-08
  • 打赏
  • 举报
回复
那就用libcurl吧。有windows版的。
移到linux上也方便,linux通常自带libcurl

http://hi.baidu.com/tc22/blog/item/bbc09422f3169dfdd7cae2dd.html
daredjever 2011-09-08
  • 打赏
  • 举报
回复
找到一个例子,是使用下面这几个MFC的类实现的下载,但是不能提供进度,也不提供断点续传

CInternetSession* m_pInetSession; //会话对象
CFtpConnection* m_pFtpConnection; //连接对象
CFtpFileFind* m_pRemoteFinder; //远程查找文件对象
CFileFind m_LocalFinder; //本地查找文件对象
daredjever 2011-09-08
  • 打赏
  • 举报
回复
对了,文件是比较大的程序安装文件大概有几十M,直接保存在内存的话,会不会有问题啊。还有下载到过程要我自己控制吗?边下载边往文件里面写。还是自动下载就下到文件里面?
我要戒烟了 2011-09-08
  • 打赏
  • 举报
回复
lz你这个是更新器吧,基本原理ls也说了,其中关键技术

ftp部分可以用ftplib (c写的开源ftp库)http://download.csdn.net/detail/tiancaiak/1201564
文件比对可以用md5

iblold 2011-09-08
  • 打赏
  • 举报
回复

BOOL GetFtpFile(const char* url, char** datbuf, int& bufsize, FILE** hfile, const char* user, const char* passwd, processfunc pfunc)
{
int port = 21;

char host[512];
strcpy(host, url + 6);

char* pStr = NULL;
if(pStr = strstr(host, "/"))
*pStr = 0;

int hostlen = pStr - host;

if(pStr = strstr(host, ":"))
{
*pStr = 0;
port = atoi(pStr + 1);
}

std::string sfile = url + 6 + hostlen + 1;

std::vector<std::string> paths;

SplitString(sfile, "/", paths);

if(paths.size() < 1)
return FALSE;

hostent* hostbyname = gethostbyname(host);
if (!hostbyname)
{
return FALSE;
}

int sockid = -1;
if((sockid = socket(PF_INET,SOCK_STREAM, 0)) == -1)
{
return FALSE;
}

sockaddr_in remote_addr;
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(port);
remote_addr.sin_addr = *((in_addr *)hostbyname->h_addr);
memset(&(remote_addr.sin_zero), 0, 8);

if(connect(sockid,(sockaddr*)&remote_addr, sizeof(remote_addr)) == -1)
{
closesocket(sockid);
return FALSE;
}

char buf[MAX_PATH];
std::string strret;
if (0 != GetResponseCode(sockid, 220, strret))
{
closesocket(sockid);
return FALSE;
}


std::string strsend = "USER ";
strsend = strsend + user + "\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 331, strret))
{
closesocket(sockid);
return FALSE;
}


strsend = "PASS ";
strsend = strsend + passwd + "\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 230, strret))
{
closesocket(sockid);
return FALSE;
}


strsend = "TYPE A\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 200, strret))
{
closesocket(sockid);
return FALSE;
}


strsend = "PASV\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 227, strret))
{
closesocket(sockid);
return FALSE;
}

std::string pasv = strret.substr(strret.find("("));
int a0, a1, a2, a3, p0, p1;
if (sscanf(pasv.c_str(),"(%d,%d,%d,%d,%d,%d)",&a0, &a1, &a2, &a3, &p0, &p1) != 6)
{
int nnn = 0;
}

for (int i = 0; i < paths.size() - 1; ++i)
{
strsend = "CWD ";
strsend = strsend + paths[i] + "\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 250, strret))
{
closesocket(sockid);
return FALSE;
}
}

strsend = "SIZE ";
strsend = strsend + paths[paths.size() - 1] + "\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 213, strret))
{
closesocket(sockid);
return FALSE;
}

ArString fsize;
SplitString(strret, " ", fsize);

int filesize = atoi(fsize[fsize.size() - 1].c_str());

BOOL bWriteFile = FALSE;

if (filesize > SIZE_USETEMP)
bWriteFile = TRUE;

strsend = "REST 0\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 350, strret))
{
closesocket(sockid);
return FALSE;
}

strsend = "RETR ";
strsend = strsend + paths[paths.size() - 1] + "\r\n";
send(sockid, strsend.c_str(), strsend.size(), 0);
if (0 != GetResponseCode(sockid, 150, strret))
{
closesocket(sockid);
return FALSE;
}

int datport = p0 * 256 + p1;
int datsockid = -1;

fd_set fdset;
timeval outtime;
outtime.tv_sec = RECV_TIME_OUT;
outtime.tv_usec = 0;

if((datsockid = socket(PF_INET,SOCK_STREAM, 0)) == -1)
{
closesocket(sockid);
return FALSE;
}

remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(datport);
remote_addr.sin_addr = *((in_addr *)hostbyname->h_addr);
memset(&(remote_addr.sin_zero), 0, 8);
if(connect(datsockid,(sockaddr*)&remote_addr, sizeof(remote_addr)) == -1)
{
closesocket(sockid);
closesocket(datsockid);
return FALSE;
}

int ret = TRUE;

FILE* fptmp = NULL;
char* pdat = NULL;

if (bWriteFile)
{
char tmppath[MAX_PATH];
GetTempPath(MAX_PATH, buf);
sprintf(tmppath, "%s\\%d.tmp", buf, ELFHash(url));


if ((fptmp = fopen(tmppath, "w+b")) == NULL)
{
closesocket(sockid);
closesocket(datsockid);
return FALSE;
}

*hfile = fptmp;
}
else
{
pdat = new char[filesize + 1];
*datbuf = pdat;
}

int recvlen = 1024;
char recvbuf[1024 + 1];

int recvedsz = 0;

while(1)
{
FD_ZERO(&fdset);
FD_SET(datsockid, &fdset);
select(datsockid + 1, &fdset, NULL, NULL, &outtime);

if (!FD_ISSET(datsockid, &fdset))
{
ret = FALSE;
break;
}

int bytesize = recv(datsockid, recvbuf, recvlen, 0);
recvbuf[bytesize] = 0;

if(bytesize < 1)
break;

if (recvedsz + bytesize > filesize)
break;

if (bWriteFile)
{
fwrite(recvbuf, 1, bytesize, fptmp);
}
else
{
memcpy(pdat, recvbuf, recvlen);
pdat += bytesize;
}

recvedsz += bytesize;

if (pfunc)
pfunc(url, filesize, recvedsz);

}

if(fptmp)
fseek(fptmp, 0, SEEK_SET);

bufsize = recvedsz;

closesocket(sockid);
closesocket(datsockid);
return ret;
}


从ftp上下载一个文件,保存到某块内存或者文件
没有断点续传
daredjever 2011-09-08
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 limang89 的回复:]

C/C++ code

//读取内容
UINT nReadCount=0;
TCHAR szDownBuffer[4096];
m_pHttpFile=(CHttpFile *)m_InternetSession.OpenURL(m_pDownLoadRequest->szDownLoadUrl,1,INTERNET_FLAG_T……
[/Quote]


这个,有点看不懂哦。。那些变量都是哪里定义的?都是什么类型的啊?
daredjever 2011-09-08
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 downmooner 的回复:]

http://www.codeproject.com/search.aspx?q=ftp+client&sbo=kw
[/Quote]

不用做成客户端,所以不用MFC的实现方法,只是在一个已经存在的程序中检测一下需要下载,就开启一个线程去下载就行了
daredjever 2011-09-08
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 luciferisnotsatan 的回复:]

那就用libcurl吧。有windows版的。
移到linux上也方便,linux通常自带libcurl

http://hi.baidu.com/tc22/blog/item/bbc09422f3169dfdd7cae2dd.html
[/Quote]

这个好像不适用,还需要包含其他的文件。越简单越好
新颖网络上传插件(StorageWebPlug)是一个支持超大文件(2GB,可扩展)上传的COM控件, 具备断点续传文件MD5验证,大大提高上传效率、节省带宽,有详细的上传进度显示支持多种脚本语言,欢迎下载体验。免费提供JavaScript SDK包。 产品特点: 1、文件上传使用增强的FTP协议,用户使用浏览器就可以上传超大文件到服务器(支持上传超过1G的文件)。 2、支持断点续传,系统智能续传未上传的文件,续传操作更简单,更方便,更快捷。 3、支持文件批量上传, 一次可以上传多个文件. 上传时有详细的状态显示(包括单个文件进度,整体进度,传输速率,剩余时间等)。 4、新颖网络免费提供JavaScript SDK包。通过新颖网络提供的封装好的JavaScript类库用户可以快速的与现有系统整合。 5、StorageWebPlug提供完善的接口和帮助文档,开发文档。开发人员可以动态设置上传保存路径, 设置允许扩展名, 允许最大大小等,可自定义强。 6、支持各种代理(HTTP, Socket4, Socket5等)。 7、组件采用多线程机制来保证上传效率。 8、支持批量文件上传, 用户可以一次性上传批量文件. 客户端可以绑定HTML表单变量, 服务端并可以接收表单变量 9、服务端文件保存路径可以随意指定,服务端文件保存路径可以灵活变化。保存路径支持网络路径。 10、为提高安全性,服务端组件可以指定用户权限 11、可以限制上传单个文件大小, 控制上传带宽上限, 允许文件扩展名, 拒绝文件扩展名等 12、上传数据时会根据网络状况来控制数据包大小, 避免网络堵塞 13、控件采用ATL编写, cab包只有59KB, 用56k的modem下载不会超过12秒 14、服务端支持Windows 2000 Server/Windows 2003 Server/Windows NT/Windows XP/Unix/Linux等操作系统 15、通过新颖网络业界领先的设计水平打造的操作界面可以帮助您的系统和产品获得更高的品质。 产品介绍:http://www.ncmem.com/service_storagewebplug.aspx 下载地址:http://www.ncmem.com/download.aspx

64,642

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧