VC++ 功能强大的API函数FindFirstFile使用介绍(附源码)
Posted dvlinker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC++ 功能强大的API函数FindFirstFile使用介绍(附源码)相关的知识,希望对你有一定的参考价值。
在处理文件的相关代码中,会频繁使用到Windows系统API函数FindFirstFile,这个函数功能很强大,很多功能都不开它。本文就根据我们在项目中使用该函数的情况,来大概地梳理一下使用FindFirstFile都可以实现哪些常用的功能。
1、FindFirstFile函数声明与WIN32_FIND_DATA结构体
我们先来看一下FindFirstFile接口的声明:
HANDLE FindFirstFileA(
[in] LPCSTR lpFileName,
[out] LPWIN32_FIND_DATAA lpFindFileData
);
第一参数是文件或文件夹名称,一般是绝对路径,是传入参数。第二个参数是关于文件信息的结构体WIN32_FIND_DATA。
如果第一个参数传入的是文件路径(单个文件的路径),则该函数返回后,获取的是该文件的信息;如果第一个参数传入的是文件夹路径(文件夹),则该函数会获取到文件夹中的第一个文件信息。
FindFirstFile函数的强大功能是因为其能获取到关于文件的WIN32_FIND_DATA结构体信息,该结构体入如下所示:(以宽字节的WIN32_FIND_DATAW为例)
typedef struct _WIN32_FIND_DATAW
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
WCHAR cFileName[ MAX_PATH ];
WCHAR cAlternateFileName[ 14 ];
#ifdef _MAC
DWORD dwFileType;
DWORD dwCreatorType;
WORD wFinderFlags;
#endif
WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
该结构体中包含文件的大量信息,比如文件的属性、文件的创建时间、文件的访问时间、文件的修改时间、文件的大小等。可以查阅MSDN上对结构体的详细说明。下面我们就来罗列一下使用该函数能够实现哪些功能。
2、判断文件是否存在
调用FindFirstFile时第一个参数传入某个文件的完整路径,能判断该文件是否存在,代码如下:
HANDLE hFile = FindFirstFile( strFilePath, &wfd );
if ( hFile == INVALID_HANDLE_VALUE )
return 0;
3、判断文件的属性
调用FindFirstFile时传入路径,可以获取该路径相关的文件属性信息(对应WIN32_FIND_DATA结构体中的dwFileAttributes字段)。可以拿该dwFileAttributes属性值,和FILE_ATTRIBUTE_DIRECTORY取与,判断该路径是文件夹还是文件。
还可以和FILE_ATTRIBUTE_HIDDEN、FILE_ATTRIBUTE_SYSTEM、FILE_ATTRIBUTE_READONLY等宏取余,依次判断文件是否是掩藏文件、是否是系统文件、是否是只读的等。相关代码如下:
WIN32_FIND_DATA wfd;
HANDLE hFindFile = FindFirstFile( strFindFileName.c_str(), &wfd );
if ( hFindFile == INVALID_HANDLE_VALUE )
return;
if ( wfd.cFileName[0] != _T('.') )
// 非本级或上级目录
if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) // 目录
//...
else if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ) // 系统文件,不处理
//...
else // 用户日志文件
//...
4、获取文件的最后修改时间
文件的最后修改时间对应WIN32_FIND_DATA结构体中的ftLastWriteTime字段。获取文件修改的最后修改时间的代码如下:
// 获取日志文件的最后修改时间
// 参数:strFilePath[in], sysTime[out]
time_t GetFileModifyTime( LPCTSTR strFilePath )
SYSTEMTIME sysTime;
HANDLE hFile = INVALID_HANDLE_VALUE;
FILETIME localFileTime;
WIN32_FIND_DATA wfd;
memset( &wfd, 0, sizeof(wfd) );
HANDLE hFile = FindFirstFile( strFilePath, &wfd );
if ( hFile == INVALID_HANDLE_VALUE )
return 0;
BOOL bRet = FileTimeToLocalFileTime( &wfd.ftLastWriteTime, &localFileTime );
if ( !bRet )
return 0;
memset( &sysTime, 0, sizeof(sysTime) );
bRet = FileTimeToSystemTime( &localFileTime, &sysTime );
if ( !bRet )
return 0;
FindClose( hFile );
// 老版本对tm结构体变量的初始化是不科学的,根据之前对本地时间和UTC时间及时区的研究,
// 将代码修改成如下的代码, by zzx 2016/04/07
struct tm tmFileTime;
memset( &tmFileTime, 0xFF, sizeof(tmFileTime) );
tmFileTime.tm_year = sysTime.wYear - 1900;
tmFileTime.tm_mon = sysTime.wMonth - 1;
tmFileTime.tm_mday = sysTime.wDay;
tmFileTime.tm_hour = sysTime.wHour;
tmFileTime.tm_min = sysTime.wMinute;
tmFileTime.tm_sec = sysTime.wSecond;
return mktime( &tmFileTime );
5、获取文件的大小
文件的大小对应WIN32_FIND_DATA结构体中的nFileSizeHigh和nFileSizeLow字段。考虑到文件比较大,考虑使用64位整型数据表示文件大小,nFileSizeHigh字段存放64位整数的高32位,nFileSizeLow字段存放64位整数的低32位。获取文件大小的代码如下:
// 计算单个文件的大小
BOOL CalcFileSize( CString strFilePath, u64& u64FileSzie )
u64FileSzie = 0;
WIN32_FIND_DATA wfd;
HANDLE hFindFile = FindFirstFile( strFilePath, &wfd );
if ( hFindFile == INVALID_HANDLE_VALUE )
return FALSE;
// 非本级或上级目录,且不是文件夹
if ( (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY )
u64 u64Temp = wfd.nFileSizeHigh;
u64FileSzie += ( u64Temp << 32 ) + wfd.nFileSizeLow;
FindClose( hFindFile );
return TRUE;
6、遍历文件夹中的文件
当给FindFirstFile传入一个文件夹路径时,该函数会获取到该文件夹下的第一个文件的信息,与FIndNextFile组合使用,完成对和一个文件夹下的所有文件进行遍历。遍历文件夹中所有文件的代码如下:
// 计算文件夹的大小,注意调用前请将n64FileSzie清零
BOOL CalcFileFolderSize( CString strFileDir, u64& u64FileSzie )
CString strFindFileName = strFileDir + _T("\\\\*.*");
WIN32_FIND_DATA wfd;
HANDLE hFindFile = FindFirstFile( strFindFileName, &wfd );
if ( hFindFile == INVALID_HANDLE_VALUE )
return FALSE;
while ( 1 )
// 将文件夹中的.和..过滤掉,之前仅判断wfd.cFileName[0]是否为‘.’是有问题的,
// 比如版本控制的代码的目录下包含掩藏的.svn文件夹,会导致文件夹大小计算有误
//(偏小)
if ( _tcscmp( wfd.cFileName, _T(".") ) != 0 &&
_tcscmp( wfd.cFileName, _T("..") ) != 0 )
// 非本级或上级目录
if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
// 目录
// 递归
CString strFilePath = strFileDir + _T('\\\\') + wfd.cFileName;
CalcFileFolderSize( strFilePath, u64FileSzie );
else
// 文件
u64 u64Temp = wfd.nFileSizeHigh;
u64FileSzie += ( u64Temp << 32 ) + wfd.nFileSizeLow;
if ( !FindNextFile( hFindFile, &wfd ) )
break;
;
FindClose( hFindFile );
return TRUE;
以上是关于VC++ 功能强大的API函数FindFirstFile使用介绍(附源码)的主要内容,如果未能解决你的问题,请参考以下文章
VC++处理窗口的常用API函数及窗口处理经验总结(附源码)
VC判断当前用户有无Administrator的权限(用EqualSid API函数判断与Admin是否在一个组的Sid)