如何遍历FTP文件(包括子目录),要纯API,不要MFC的?

时间:2022-06-04 12:50:19

//open ftp directoy
HINTERNET hInet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, 0,
INTERNET_FLAG_DONT_CACHE);//打开目录,不缓存
HINTERNET hFtp = InternetConnect(hInet, lpszIP, dwPort, lpszUID, lpszPWD, INTERNET_SERVICE_FTP,
INTERNET_FLAG_PASSIVE, 0);//FTP,被动模式
WIN32_FIND_DATA fd;
HINTERNET hFind = FtpFindFirstFile(hFtp, "*.*", &fd, 0, 0);
while (hFind)
{
if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
{
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
if (fd.cFileName & FILE_ATTRIBUTE_DIRECTORY)
{
//不会写了...
}
if (!InternetFindNextFile(hFind, &fd))
break;
}
if (hFind)
InternetCloseHandle(hFind);
if (hFtp)
InternetCloseHandle(hFtp);
if (hInet)
InternetCloseHandle(hInet);
return bRes;
}

好象遍历不行,出现第二个:
HINTERNET hFind = FtpFindFirstFile(hFtp, "*.*", &fd, 0, 0);
时,HFind=0,错误码12110

11 个解决方案

#1


你可以查找下“VC 遍历文件”方面的代码,跟这代码有点类似的

#2



//vc遍历文件夹
#include "stdafx.h"
#include <string>
#include <Windows.h>
#include <list>
#include <io.h>

using namespace std;

BOOL FindAllFiles(string strDirectory, list<string> &ml, string &strALL);
int _tmain(int argc, _TCHAR* argv[])
{
string strDirectory = "F:\\qudong";
list<string> ml;
string strALL = "";
FindAllFiles(strDirectory, ml, strALL);
return 1;
}
//参数1:文件夹路径 参数2:获取的所有文件名 参数3:获取的所有文件名字符串(用\n分开)
BOOL FindAllFiles(string strDirectory, list<string> &ml, string &strALL)
{
_finddata_t c_file;
c_file.attrib =_MAX_PATH;
string strTmpPath =  strDirectory + "\\*.*";
intptr_t hFile = _findfirst(strTmpPath.c_str(), &c_file);
if((HANDLE)hFile == INVALID_HANDLE_VALUE)
{
return TRUE;
}
do
{
if( c_file.attrib & _A_SUBDIR && string(c_file.name) != "." && string(c_file.name) != ".." && !(c_file.attrib & _A_SYSTEM) )
{

FindAllFiles(strDirectory + "\\" + c_file.name, ml, strALL);
}
else
{
if(string(c_file.name) != "." && string(c_file.name) != "..")
{
if(c_file.size > 0)
{
ml.push_back(strDirectory + "\\" + c_file.name);
strALL += strDirectory + "\\" + c_file.name + "\n";
}
}
}
}while(_findnext(hFile, &c_file) == 0);
_findclose(hFile);
return TRUE;
}


#3


你的代码好象是遍历本地磁盘的,我要的是遍历FTP下的.

#4


你把中间那个遍历的写个递归函数

#5


		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
InternetCloseHandle(hFind);//必须关闭上一级目录的句柄,才能进入子目录遍历//但上级目录搜到哪里了,如何得知
FtpSetCurrentDirectory(hFtp, fd.cFileName);
EumnFile(hFtp);
}
 

我试了一下,遍历子目录时,上一级目录的遍历句柄必须关闭,不然下一级获得的是hFind是空的
我关闭了上一级目录句柄,可以成功遍历下一级目录,但上一级搜到哪里了,如何得知,因为已经关了上一级的hFind

#6


网上说,好象就是不能遍历,只能用容器先把目录保存起来,一层一层的执行发现目录下文件的函数.

#7



//枚举FTP
void EnumFiles(HINTERNET hFtp, vector<CString>& strPaths, int iPath, vector<CString>& strFiles)
{
CString strPath = "";
if (!strPaths.empty())
strPath = "/" + strPaths[iPath];
FtpSetCurrentDirectory(hFtp, strPath);
WIN32_FIND_DATA fd;
HINTERNET hFind = FtpFindFirstFile(hFtp, "*.*", &fd, 0, 0);
while (hFind)
{
if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
{
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
CString strRemoteFile;
if (!strPath.IsEmpty())
strRemoteFile = strPaths[iPath] + "/" + fd.cFileName;
else
strRemoteFile = fd.cFileName;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
strPaths.push_back(strRemoteFile);
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
CString strLocalFile = strRemoteFile;
strLocalFile.Replace("/", "\\");
if (::PathFileExists(strLocalFile))
{//比较文件大小,可根据实际需要比较日期,版本等.
DWORD nFileSize = 0;
WIN32_FIND_DATA wfd;
HANDLE hFile = FindFirstFile(fd.cFileName, &wfd);
if (hFile != INVALID_HANDLE_VALUE)
{
nFileSize = wfd.nFileSizeLow;
FindClose(hFile);
}
if (nFileSize == fd.nFileSizeLow)
{
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
}
strFiles.push_back(strRemoteFile);
if (!InternetFindNextFile(hFind, &fd))
break;
}
if (hFind)
InternetCloseHandle(hFind);
}

BOOL FTPDownloadFiles(LPCTSTR lpszIP, DWORD dwPort, LPCTSTR lpszUID, LPCTSTR lpszPWD)
{
///////////////////////
//open ftp directoy and get needs update files
HINTERNET hInet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, 0,
INTERNET_FLAG_DONT_CACHE);//打开目录,不缓存
HINTERNET hFtp = InternetConnect(hInet, lpszIP, dwPort, lpszUID, lpszPWD, INTERNET_SERVICE_FTP,
INTERNET_FLAG_PASSIVE, 0);//FTP,被动模式
vector<CString> strPaths;//路径暂存
vector<CString> strFiles;//需要下载的文件列表
EnumFiles(hFtp, strPaths, 0, strFiles);
for (int i = 0; i < strPaths.size(); i ++)
{
EnumFiles(hFtp, strPaths, i, strFiles);//枚举FTP文件
}
//根据strFiles的内容下载文件...

我现在是这样做的,暂时还没发现问题...

#8


引用 7 楼 firefly3233 的回复:
C/C++ code

//枚举FTP
void EnumFiles(HINTERNET hFtp, vector<CString>&amp; strPaths, int iPath, vector<CString>&amp; strFiles)
{
    CString strPath = "";
    if (!strPaths.empty())
        strPath = "……


都用CString了,还说不用MFC

#9


那我建议你还是查一查ftp协议吧,看协议中用什么代码来获得ftp服务器上的文件目录,至于遍历,可以不断发送申请目录命令,只要还有目录,就申请,然后,将所有文件名以及所处的位置保存就可以了。。。。。。和遍历自己电脑没什么区别,只是不断发送命令而已。。。
这样,就是自己写一个ftp客户端,应该也不是什么问题。。。

#10


ftp的本质还是socket嘛

#11


引用 8 楼 magicfuzzx 的回复:
都用CString了,还说不用MFC

想做成MFC包含较少的DLL,CString当然没问题,CInternetSession,CFtpConnection,CFtpFileFind等和网络有关的类,运行中报错,因为我并没有完全依赖MFC,其它类没问题,所以...

#1


你可以查找下“VC 遍历文件”方面的代码,跟这代码有点类似的

#2



//vc遍历文件夹
#include "stdafx.h"
#include <string>
#include <Windows.h>
#include <list>
#include <io.h>

using namespace std;

BOOL FindAllFiles(string strDirectory, list<string> &ml, string &strALL);
int _tmain(int argc, _TCHAR* argv[])
{
string strDirectory = "F:\\qudong";
list<string> ml;
string strALL = "";
FindAllFiles(strDirectory, ml, strALL);
return 1;
}
//参数1:文件夹路径 参数2:获取的所有文件名 参数3:获取的所有文件名字符串(用\n分开)
BOOL FindAllFiles(string strDirectory, list<string> &ml, string &strALL)
{
_finddata_t c_file;
c_file.attrib =_MAX_PATH;
string strTmpPath =  strDirectory + "\\*.*";
intptr_t hFile = _findfirst(strTmpPath.c_str(), &c_file);
if((HANDLE)hFile == INVALID_HANDLE_VALUE)
{
return TRUE;
}
do
{
if( c_file.attrib & _A_SUBDIR && string(c_file.name) != "." && string(c_file.name) != ".." && !(c_file.attrib & _A_SYSTEM) )
{

FindAllFiles(strDirectory + "\\" + c_file.name, ml, strALL);
}
else
{
if(string(c_file.name) != "." && string(c_file.name) != "..")
{
if(c_file.size > 0)
{
ml.push_back(strDirectory + "\\" + c_file.name);
strALL += strDirectory + "\\" + c_file.name + "\n";
}
}
}
}while(_findnext(hFile, &c_file) == 0);
_findclose(hFile);
return TRUE;
}


#3


你的代码好象是遍历本地磁盘的,我要的是遍历FTP下的.

#4


你把中间那个遍历的写个递归函数

#5


		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
InternetCloseHandle(hFind);//必须关闭上一级目录的句柄,才能进入子目录遍历//但上级目录搜到哪里了,如何得知
FtpSetCurrentDirectory(hFtp, fd.cFileName);
EumnFile(hFtp);
}
 

我试了一下,遍历子目录时,上一级目录的遍历句柄必须关闭,不然下一级获得的是hFind是空的
我关闭了上一级目录句柄,可以成功遍历下一级目录,但上一级搜到哪里了,如何得知,因为已经关了上一级的hFind

#6


网上说,好象就是不能遍历,只能用容器先把目录保存起来,一层一层的执行发现目录下文件的函数.

#7



//枚举FTP
void EnumFiles(HINTERNET hFtp, vector<CString>& strPaths, int iPath, vector<CString>& strFiles)
{
CString strPath = "";
if (!strPaths.empty())
strPath = "/" + strPaths[iPath];
FtpSetCurrentDirectory(hFtp, strPath);
WIN32_FIND_DATA fd;
HINTERNET hFind = FtpFindFirstFile(hFtp, "*.*", &fd, 0, 0);
while (hFind)
{
if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0)
{
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
CString strRemoteFile;
if (!strPath.IsEmpty())
strRemoteFile = strPaths[iPath] + "/" + fd.cFileName;
else
strRemoteFile = fd.cFileName;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
strPaths.push_back(strRemoteFile);
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
CString strLocalFile = strRemoteFile;
strLocalFile.Replace("/", "\\");
if (::PathFileExists(strLocalFile))
{//比较文件大小,可根据实际需要比较日期,版本等.
DWORD nFileSize = 0;
WIN32_FIND_DATA wfd;
HANDLE hFile = FindFirstFile(fd.cFileName, &wfd);
if (hFile != INVALID_HANDLE_VALUE)
{
nFileSize = wfd.nFileSizeLow;
FindClose(hFile);
}
if (nFileSize == fd.nFileSizeLow)
{
if (!InternetFindNextFile(hFind, &fd))
break;
continue;
}
}
strFiles.push_back(strRemoteFile);
if (!InternetFindNextFile(hFind, &fd))
break;
}
if (hFind)
InternetCloseHandle(hFind);
}

BOOL FTPDownloadFiles(LPCTSTR lpszIP, DWORD dwPort, LPCTSTR lpszUID, LPCTSTR lpszPWD)
{
///////////////////////
//open ftp directoy and get needs update files
HINTERNET hInet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, 0,
INTERNET_FLAG_DONT_CACHE);//打开目录,不缓存
HINTERNET hFtp = InternetConnect(hInet, lpszIP, dwPort, lpszUID, lpszPWD, INTERNET_SERVICE_FTP,
INTERNET_FLAG_PASSIVE, 0);//FTP,被动模式
vector<CString> strPaths;//路径暂存
vector<CString> strFiles;//需要下载的文件列表
EnumFiles(hFtp, strPaths, 0, strFiles);
for (int i = 0; i < strPaths.size(); i ++)
{
EnumFiles(hFtp, strPaths, i, strFiles);//枚举FTP文件
}
//根据strFiles的内容下载文件...

我现在是这样做的,暂时还没发现问题...

#8


引用 7 楼 firefly3233 的回复:
C/C++ code

//枚举FTP
void EnumFiles(HINTERNET hFtp, vector<CString>&amp; strPaths, int iPath, vector<CString>&amp; strFiles)
{
    CString strPath = "";
    if (!strPaths.empty())
        strPath = "……


都用CString了,还说不用MFC

#9


那我建议你还是查一查ftp协议吧,看协议中用什么代码来获得ftp服务器上的文件目录,至于遍历,可以不断发送申请目录命令,只要还有目录,就申请,然后,将所有文件名以及所处的位置保存就可以了。。。。。。和遍历自己电脑没什么区别,只是不断发送命令而已。。。
这样,就是自己写一个ftp客户端,应该也不是什么问题。。。

#10


ftp的本质还是socket嘛

#11


引用 8 楼 magicfuzzx 的回复:
都用CString了,还说不用MFC

想做成MFC包含较少的DLL,CString当然没问题,CInternetSession,CFtpConnection,CFtpFileFind等和网络有关的类,运行中报错,因为我并没有完全依赖MFC,其它类没问题,所以...