EVC下Ftp遍历下载所有文件夹(原创)
本文讨论在Evc下遍历ftp站点的文件并下载,google了很多天,找到相关资料,但在evc下应用的很少,此文总结方法并应用到evc,以共享。
ftp站点的访问有很多方法,本文使用InternetOpen,InternetConnect两函数来连接,因在evc环境下并不支持CFtpFileFind类,可用FtpFindFirstFile,InternetFindNextFile来遍历文件夹,用FtpGetFile下载文件,此方法是win API函数,在多种windows开发平台上都可以使用。
这几个函数的结合在google上可以轻易搜索到,在此介绍下此次开发过程中遇到的问题:
1 关于evc下遍历文件夹的方法
vc下遍历ftp文件夹的方法很简单,又专门的类CFtpFileFind,通过此类可直接查找文件,但是evc下不支持这个类的使用。在windows遍历文件夹使用FindFirstFile和FindNextFile,此方法可访问本地和局域网的文件夹,如访问:"192.168.1.230//Share",注意此时的文件夹中的斜杠的数量,必须是这种格式的,但此方法无法访问远程的ftp站点,最终找到FtpFindFirstFile,InternetFindNextFile结合的方法,可以使用;
2 使用FtpFindFirstFile,InternetFindNextFile查找的文件夹类型
ftp站点下的每个文件夹下都有两个文件夹"."和".."存在,"."代表本目录路径,".."代表上一级路径,所以在搜索到文件夹时需做判断排除此文件夹。
3 使用FtpFindFirstFile后无法用InternetFindNextFile继续查找下一个文件或文件夹
在使用函数InternetOpen(_T("ftp"),INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0)时注意参数设置,起初我最后一个参数使用了INTERNET_FLAG_ASYNC,MSDN上的解释是Makes only asynchronous requests on handles descended from the handle returned from this function. Only the InternetOpen function uses this flag. 我尚未弄清该参数的具体意义,起初使用是参考其他网友的版本,大家可研究下。还有注意的是第一个参数不能为NULL,否则open出错。
4 使用FtpFindFirstFile查询后,发现文件夹遍历进入后,再搜索时发现FtpFindFirstFile的返回值为0
在这里要注意的是,在进入下一级文件夹后,必须先调用InternetCloseHandle(hFind)!!!否则结果就像上面描述的那样了,返回0。
这样使用后,会存在递归调用下载的问题,因为程序逻辑是,如果发现文件夹即递归进入,之前的hFind已经被关闭,这样递归返回后,其余文件无法下载了,所以此处采用的方法是,在递归发现文件夹后把文件夹名保存,下载此目录下的其他文件,全部完毕后,再调用文件夹名递归进入下一级文件夹,这样之前的hFind被关闭后也不存在返回的问题了。
5 自己经验,供大家共享,如有问题,欢迎反馈!
以下是主要代码,经测试通过可以在evc下运行。
头文件:
#include "wininet.h"
#include <afxinet.h>
project settings->link->添加wininet.lib
// 递归创建目录
void CreateAllDirectories(CString strDir)
{
if(strDir.GetLength()!=0)
{
if(strDir.Right(1)=="//")
strDir=strDir.Left(strDir.GetLength()-1);
// 目录存在则返回
if(GetFileAttributes(strDir)!=-1)
return;
// 递归创建目录
int nFound = strDir.ReverseFind('//');
CreateAllDirectories(strDir.Left(nFound));
// 实际创建目录
CreateDirectory(strDir,NULL);
}
}
//递归下载
void FtpEnumDirectory(HINTERNET hConnect,CString szSourceDir,CString szSaveDir)
{
CString szFileName;
CStringArray dirs;
WIN32_FIND_DATA pData;
HINTERNET hFind;
// Start enumeration and get file handle
if(szSourceDir.GetAt(szSourceDir.GetLength()-1)!='/')
szSourceDir+="/";
hFind = FtpFindFirstFile(hConnect, szSourceDir+"*.*", &pData, 0, 0);
if (!hFind)
{
if(GetLastError() == ERROR_NO_MORE_FILES)
{
InternetCloseHandle(hFind);
}
else
{
AfxMessageBox(_T("FindFirst failed"));
InternetCloseHandle(hFind);
return ;
}
}
else
//do
{
szFileName=pData.cFileName;
if(pData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
if((szFileName!=".") && (szFileName != "..")) //content is sub dir
{
//递归
FtpSetCurrentDirectory(hConnect,szSourceDir+szFileName);
dirs.Add(szFileName);
}
}
else //download
{
CreateAllDirectories(szSaveDir);
if(!FtpGetFile(hConnect,szSourceDir+szFileName,szSaveDir+"//"+szFileName,FALSE,FILE_ATTRIBUTE_NORMAL,FTP_TRANSFER_TYPE_ASCII | INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD ,NULL))
{
AfxMessageBox(_T("FtpGetFile failed"));
return;
}
}
}//while(InternetFindNextFile(hFind,&pData));
do
{
if(!InternetFindNextFile(hFind,&pData))
{
if(GetLastError() == ERROR_NO_MORE_FILES)
{
InternetCloseHandle(hFind);
break;
}
else
{
AfxMessageBox(_T("FindNext failed"));
InternetCloseHandle(hFind);
return;
}
}
else
{
szFileName=(LPCTSTR) &pData.cFileName;
// Entry is a directory, mark it as such
if(pData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
if((szFileName!=".") && (szFileName != "..")) //content is sub dir
{
//递归
FtpSetCurrentDirectory(hConnect,szSourceDir+szFileName);
dirs.Add(szFileName);
}
}
else //download
{
CreateAllDirectories(szSaveDir);
if(!FtpGetFile(hConnect,szSourceDir+szFileName,szSaveDir+"//"+szFileName,FALSE,FILE_ATTRIBUTE_NORMAL,FTP_TRANSFER_TYPE_ASCII | INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD ,NULL))
{
AfxMessageBox(_T("FtpGetFile failed"));
return;
}
}
}
} while(TRUE);
for(int i=0;i<dirs.GetSize();i++)
{
//InternetCloseHandle(hFind);
szFileName=dirs.GetAt(i);
FtpEnumDirectory(hConnect,szSourceDir+szFileName,szSaveDir+"//"+szFileName);
}
return;
}
//连接ftp
BOOL FtpDownloadFiles (CString IpAddress,CString szftpDir,CString szSaveDir)
{
HINTERNET hConnect,hHost;
hHost=InternetOpen(_T("ftp"),INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
if(!hHost)
{
CString str;
str.Format(_T("Open Error: %Xh"),GetLastError());
AfxMessageBox(str);
return FALSE;
}
hConnect=InternetConnect(hHost,IpAddress,INTERNET_DEFAULT_FTP_PORT,NULL,NULL,INTERNET_SERVICE_FTP,0,0);
if(!hConnect)
{
AfxMessageBox(_T("InternetConnect failed"));
InternetCloseHandle(hHost);
return FALSE;
}
FtpEnumDirectory(hConnect,szftpDir,szSaveDir);
InternetCloseHandle(hConnect);
InternetCloseHandle(hHost);
return TRUE;
}
void CRFtpDownDlg::OnRdown()
{
// TODO: Add your control notification handler code here
CString ip=_T("192.168.1.150");
CString szftpDir=_T("/");
CString szSaveDir=_T("/ftp");
if(FtpDownloadFiles(ip,szftpDir,szSaveDir))
AfxMessageBox(_T("Download Finished!"));
}
附:VC下遍历下载代码,使用CFtpFindFile类(本文参考内容,根据其思路改进,出自csdn论坛,感谢达人!)
#include <afxinet.h>
//2 递归下载文件
void GetTree(CFtpConnection* objConn,CString strSour,CString strDest)
{
CStringArray dirList;
CFtpFileFind ftpFind(objConn);
if(strSour.GetAt(strSour.GetLength()-1)!='/')strSour+="/";
BOOL bContinue = ftpFind.FindFile(strSour+"*");
if (!bContinue)
{
ftpFind.Close();
return;
}
BOOL bDir = FALSE;
CString strFileName, strFilePath;
while (bContinue)
{
bContinue = ftpFind.FindNextFile();
strFileName = ftpFind.GetFileName();
strFilePath = ftpFind.GetFilePath();
if (ftpFind.IsDirectory())
{
bDir = TRUE;
dirList.Add(strFileName);
}
else
{
// 创建目录
::CreateAllDirectories(strDest);
// 执行下载
objConn->GetFile(strFilePath,strDest+"//"+strFileName,FALSE);
//AfxMessageBox(strFilePath+"->"+strDest+"//"+strFileName);
}
}
ftpFind.Close();
int count=dirList.GetSize();
for(int i=0;i<count;i++)
{
strFileName = dirList.GetAt(i);
GetTree(objConn,strSour+strFileName,strDest+"//"+strFileName);
}
dirList.RemoveAll();
}
// 3 建立FTP连接
void CFtpDlg::OnButtonDo()
{
CString strServerName = "192.168.0.199";
CString strUserName = "administrator";
CString strPassword = "zhrmghg";
CString strSourPath = "/";
CString strDestPath = "d://abc";
try
{
CInternetSession* objSession = new CInternetSession(strServerName,1);
CFtpConnection* objConn = objSession->GetFtpConnection(strServerName,strUserName,strPassword);
//objConn->GetFile(strSourPath,strDestPath,FALSE);
GetTree(objConn,strSourPath,strDestPath);
objConn->Close();
delete objConn;
objSession->Close();
delete objSession;
}
catch(CInternetException* pEx)
{
TCHAR szErr[1024];
if (pEx->GetErrorMessage(szErr, 1024))
AfxMessageBox(szErr, MB_OK);
else
AfxMessageBox("sdfs", MB_OK);
pEx->Delete();
}
}