关闭

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

标签: MFCWin32 API遍历文件系统
441人阅读 评论(0) 收藏 举报
分类:

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

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


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:305341次
    • 积分:5744
    • 等级:
    • 排名:第4680名
    • 原创:149篇
    • 转载:0篇
    • 译文:128篇
    • 评论:29条
    文章分类
    最新评论