[MFC]利用Win32 API遍历文件系统

原创 2015年07月09日 16:49:48

1. 遍历文件系统所需的工具:

    1) MFC的CFile并没有对遍历文件系统的功能进行面向对象包装,因此遍历文件系统必须使用较为原始、底层的Win32 API;

    2) 大致步骤是:

         i. 使用::SetCurrentDirectory函数设定当前处于什么目录下(Windows中叫做文件夹);

         ii. 使用::FindFirstFile获取当前文件夹下的第一个文件的“查找句柄”,注意!不是该文件的文件句柄,而是一种查找句柄,Win32使用了一种“查找结构”来支持文件的遍历;

         iii. 接着反复调用::FindNextFile获取下一个文件的“查找句柄”,其中可以判断该文件是否为文件夹,如果是文件夹的话还可以递归地进入该文件夹进行遍历;

    3) 在使用Find函数的时候会将查找的文件的相关信息填写到一个叫做“查找结构”的结构体中,然后可以利用该结构体中该文件的信息进行一些操作,该结构就是WIN32_FIND_DATA结构体:

struct WIN32_FIND_DATA {
	DWORD dwFileAttributes; // 文件属性,比如是文件还是文件夹等
	FILETIME ftCreationTime; // 文件创建时间
	FILETIME ftLastAccessTime; // 最近一次文件被访问的时间(包括读写)
	FILETIME ftLastWriteTime; // 最近一次文件被写的时间
	CHAR cFileName[MAX_PATH]; // 文件的完整绝对路径
	...
};
!要判断查找的文件是文件还是文件夹只需要看一下dwFileAttributes的位掩码FILE_ATTRIBUTE_DIRECTORY是否为1就行了

    4) FindFirstFile:

         i. HANDLE ::FindFirstFile(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);

         ii. 第一个参数是目标文件名,可以使用通配符,一般在遍历的时候查找的第一个文件都用_T("*.*")来表示;

         iii. 第二个参数就是上面所说的WIN32_FIND_DATA结构的指针,查找到的文件的相关信息就保存在该结构体中;

         iv. 返回值就是相关的“查找句柄”,而不是文件句柄hFile,也不是WIN32_FIND_DATA的句柄,而是Win32 API内部维护的一个查找体的句柄,如果失败则返回INVALID_HANDLE_VALUE;

    5) FindNextFile:

         i. BOOL ::FindNextFile(HANDLE hFindFile, LPWIN32_FIND_DATA lpFindData);

         ii. 第一个参数就是上一次查找得到的查找句柄,通常在调用FindFirstFile之后将返回值传给该参数进行迭代查找,查找的文件的信息同样放在lpFindData中;

         iii. 调用成功返回TRUE,否则返回FALSE;

    6) SetCurrentDirectory:

         i. BOOL ::SetCurrentDirectory(LPCTSTR lpPathName);

         ii. 将当前所在目录设成lpPathName所指定的目录,可以是绝对路径也可以是相对路径;

         iii. 有时可能提供的路径有问题,因此调用失败返回FALSE,成功则为TRUE;

    7) GetCurrentDirectory:获取当前路径

         i. BOOL ::GetCurrentDirectory(DWORD nBufferLength, LPSTR lpBuffer);

         ii. 第一个参数是缓冲区能接受的字符个数,注意!是字符个数而不是字节数,这最主要是兼容Unicode;

         iii. lpBuffer就是缓冲区;

         iv. 为了兼容Unicode最好这样调用:::GetCurrentDirectory(sizeof(szPath) / sizeof(TCHAR), szPath);


2. 示例——递归遍历一个文件夹:

void trace_t(int nCount) // 在一行的开头打nCount个制表符以示文件夹的层级
{
	while (nCount)
	{
		TRACE(_T("\t"));
		nCount--;
	}
}

void EnumerateFile(int nLevel) // 递归遍历文件系统
{
	WIN32_FIND_DATA fd;
	HANDLE hFind = ::FindFirstFile(_T("*.*"), &fd); // 开始从任意位置查找

	if (hFind != INVALID_HANDLE_VALUE) // 注意FindFirstFile的返回值是HANDLE
	{
		do 
		{
			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				CString name = fd.cFileName;
				if (name != _T(".") && name != _T(".."))
				{
					trace_t(nLevel); // 先打印表示所在层级的制表符
					TRACE(_T("[D]%s\n"), fd.cFileName); // 文件夹用[D]来表示

					::SetCurrentDirectory(fd.cFileName); // 进入刚查找的文件夹
					EnumerateFile(nLevel + 1); // 如果是文件夹则递归往下遍历
					::SetCurrentDirectory(_T("..")); // 遍历完后返回上层文件夹中继续遍历
				}
			}
			else
			{
				CString name = fd.cFileName;
				trace_t(nLevel);
				TRACE(_T("[F]%s\n"), fd.cFileName); // 普通文件用[F]来表示
			}
		} while (::FindNextFile(hFind, &fd)); // 继续查找,注意FindNextFile返回值是BOOL
		::FindClose(hFind);
	}
}

void CMainWindow::OnLButtonDown(UINT nFlags, CPoint point)
{
	::SetCurrentDirectory(_T("C:\\Proj")); // 设置遍历目标文件夹
	EnumerateFile(0); // 刚开始时层级是0,即第一层中的文件名前面没有制表符
}

结果如下:

[D]mfc
	[D]code
		[F].Hello.h.swp
		[F]Hello.cpp
		[F]Hello.h
	[D]p1
		[D]Hello
			[D]Debug
				[F]Hello.exe
				[F]Hello.ilk
				[F]Hello.obj
				[F]Hello.pch
				[F]Hello.pdb
				[F]vc60.idb
				[F]vc60.pdb
			[F]Hello.cpp
			[F]Hello.dsp
			[F]Hello.dsw
			[F]Hello.h
			[F]Hello.ncb
			[F]Hello.opt
			[F]Hello.plg
		[D]Shapes
			[F]ChildView.cpp
			[F]ChildView.h
			[D]Debug
			[F]MainFrm.cpp
			[F]MainFrm.h
			[F]ReadMe.txt
			[D]res
				[F]Shapes.ico
				[F]Shapes.rc2
			[F]Resource.h
			[F]Shapes.aps
			[F]Shapes.clw
			[F]Shapes.cpp
			[F]Shapes.dsp
			[F]Shapes.dsw
			[F]Shapes.h
			[F]Shapes.ncb
			[F]Shapes.opt
			[F]Shapes.rc
			[F]StdAfx.cpp
			[F]StdAfx.h
		[D]Test
			[D]Debug
				[F]Test.exe
				[F]Test.ilk
				[F]Test.obj
				[F]Test.pch
				[F]Test.pdb
				[F]vc60.idb
				[F]vc60.pdb
			[F]Test.cpp
			[F]Test.dsp
			[F]Test.dsw
			[F]Test.h
			[F]Test.ncb
			[F]Test.opt
			[F]Test.plg
		[D]TicTac
			[D]Debug
				[F]TicTac.exe
				[F]TicTac.ilk
				[F]TicTac.obj
				[F]TicTac.pch
				[F]TicTac.pdb
				[F]vc60.idb
				[F]vc60.pdb
			[F]TicTac.cpp
			[F]TicTac.dsp
			[F]TicTac.dsw
			[F]TicTac.h
			[F]TicTac.ncb
			[F]TicTac.opt
			[F]TicTac.plg
	[D]p3
		[D]TicTac
			[D]Debug
				[F]TicTac.exe
				[F]TicTac.ilk
				[F]TicTac.obj
				[F]TicTac.pch
				[F]TicTac.pdb
				[F]vc60.idb
				[F]vc60.pdb
			[F]TicTac.cpp
			[F]TicTac.dsp
			[F]TicTac.dsw
			[F]TicTac.h
			[F]TicTac.ncb
			[F]TicTac.opt
			[F]TicTac.plg
		[D]TT
			[D]Debug

可以清楚的看到层级关系!


相关文章推荐

Win32 获取磁盘剩余空间+遍历文件目录+wchar_t与char互转

函数GetDiskFreeSpaceEx声明如下:   WINBASEAPI BOOL WINAPI GetDiskFreeSpaceExA(     __in_opt LPCSTR lp...
  • ypist
  • ypist
  • 2012年04月17日 10:09
  • 1531

win32 遍历 文件夹中文件

#include #include //#include using namespace std; int main() { _finddata_t FileInfo; strin...

win32api编程——文件系统长文件名测试

问题引入: 有些不同的文件系统对文件名长度的支持是不一样的,具体请参考维基百科...

C#使用WIN32API来遍历文件和目录

我们有时需要遍历某个目录下的文件和子目录,可以使用System.IO.DirectoryInfo.GetDirectories或GetFiles来获得目录下的所有的文件和子目录,当这个目录下的内容比较...

系统理解Win32 API和MFC(下)

二、MFC的概念模型前面我们研究了WIN32 API的“领域模型”,对它有较全面的认识。下面,对MFC概念模型的研究,我们把重点放在对app framework的研究上。app framewo...

文件系统过滤驱动开发(一)—Win32底层开发小组

    声明:本文无太多新意,只是介绍下学习经验,大神级人物(如总监大人)请略过,谢谢合作>_这本书,搭了个环境之后,其实也没碰很多,编了个经典的Hello,World!之后就无太多后续动作,暑假嘛,...
  • gaa_ra
  • gaa_ra
  • 2011年03月18日 18:08
  • 1792

Win32文件系统1-磁盘驱动器

[获取驱动器信息] 所用到的API函数: GetLogicalDrivers:获取本机所有逻辑驱动器,以位标志的形式返回 GetLogicalDriverString:获取本机所有逻辑驱动器,以驱动器...

[Win32] 文件系统操作

上一节讲了文件同步读写,这次就说说文件系统的操作。 文件系统,简单理解一下,因为磁盘上数据有他的存储方式,而应用程序如果对每种磁盘格式都有了解的话,无疑太难实现,而且兼容性也无法保证,因此,操作系统就...

基于c++使用win32 api遍历文件夹

在做图像处理算法过程中,有时需要将算法应用于某个文件夹下的所有图片,然后对比查看处理效果。有时文件夹内还有子文件夹,这时就需要递归遍历当前文件夹,以将算法应用于所有图片。遍历文件夹程序网上可以找到一些...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[MFC]利用Win32 API遍历文件系统
举报原因:
原因补充:

(最多只允许输入30个字)