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

daredjever 2011-09-08 10:59:29
大家好:
现在需要去FTP服务器下载一个文件,本地程序检测需要下载的是就去下载,本地要显示下载进度,最好支持断点续传功能,哪位做过指点一下?
看网上有些是用MFC做的,能不能不用MFC的类?
...全文
410 13 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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]

这个好像不适用,还需要包含其他的文件。越简单越好

65,187

社区成员

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

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