C/C++遍历目录下的所有文件(Windows篇,超详细)

您所在的位置:网站首页 shell脚本遍历目录的目录 C/C++遍历目录下的所有文件(Windows篇,超详细)

C/C++遍历目录下的所有文件(Windows篇,超详细)

2023-05-06 10:55| 来源: 网络整理| 查看: 265

注:

1. 本文讨论的是怎么用Windows API遍历目录下的所有文件。除Windows API,还有一种Windows/Linux通用的方式,使用。

2. 本文部分翻译自MSDN,翻译可能不准确。

 

WIN32_FIND_DATA结构

 

遍历目录下的文件需要用到WIN32_FIND_DATA结构。实际上有两种结构:WIN32_FIND_DATAA和WIN32_FIND_DATAW。A和W分别代表ASCII和宽字符(Unicode)。定义UNICODE宏时,WIN32_FIND_DATA指WIN32_FIND_DATAW;否则指WIN32_FIND_DATAA。

 

下面是两个结构的定义(minwinbase.h,VS2015):

 

typedef struct _WIN32_FIND_DATAA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; _Field_z_ CHAR cFileName[ MAX_PATH ]; _Field_z_ CHAR cAlternateFileName[ 14 ]; #ifdef _MAC DWORD dwFileType; DWORD dwCreatorType; WORD wFinderFlags; #endif } WIN32_FIND_DATAA; typedef struct _WIN32_FIND_DATAW { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; _Field_z_ WCHAR cFileName[ MAX_PATH ]; _Field_z_ WCHAR cAlternateFileName[ 14 ]; #ifdef _MAC DWORD dwFileType; DWORD dwCreatorType; WORD wFinderFlags; #endif } WIN32_FIND_DATAW;

 

关于_MAC宏的部分可以忽略, 这是有历史原因的——曾今Microsoft是Mac的最大开发者,为了方便Windows上的应用移植到Mac上,就使用_MAC宏,如果是Mac操作系统_MAC就是有定义的。(根据Stack Overflow)因为这里说的是Windows,就先把这个放一边。

 

下面是每个结构成员的含义:

 

dwFileAttributes

 

一个文件(或路径)的文件属性。

 

文件属性常量:

 

FILE_ATTRIBUTE_ARCHIVE(0x20):文件或目录是档案文件或目录。应用程序使用这种属性标记文件,表示备份或移除。

FILE_ATTRIBUTE_COMPRESSED(0x800):文件或目录是压缩的。对于一个文件,其中的所有数据都是压缩的。对于一个目录,对于新创建的文件和子目录默认压缩。

FILE_ATTRIBUTE_DEVICE(0x40):这个值保留给系统使用。

FILE_ATTRIBUTE_DIRECTORY(0x10):表示这是一个目录。

FILE_ATTRIBUTE_ENCRYPTED(0x10):文件或目录是加密的。对于一个文件,所有的数据流都被加密了。对于一个目录,对于新创建的文件和子目录默认加密。

FILE_ATTRIBUTE_HIDDEN(0x2):文件或目录是隐藏的。遍历文件夹时一般不包括它们。

FILE_ATTRIBUTE_INTEGRITY_STREAM(0x8000):路径或用户数据流被设置为integrity(只有ReFS volume支持)。遍历文件夹时一般不包括它们。Integrity设置在文件重命名之后依然保留。如果一个文件被复制,目标文件将会是integrity,不管源文件或目标路径是否是integrity。

 

FILE_ATTRIBUTE_NORMAL(0x80):文件没有任何其它属性。只能单独使用。

 

FILE_ATTRIBUTE_NOT_CONTEXT_INDEXED(0x2000):文件或目录不会被context indexing service标索引。

FILE_ATTRIBUTE_READONLY(0x1):文件为只读。程序可以读取该文件,但不能写入或删除。此属性不适用于目录。

 

……(太多了,有时间再全部列举)

 

顺带提一下位标记(bit flags)。

 

如你所见,所有的文件属性常量写成二进制都只有一位是1,剩下的都是0。对于dwFileAttributes,将其写成二进制的形式,它的一些位的值是有含义的——例如个位表示是否是只读的(FILE_ATTRIBUTE_READONLY是1),16位表示是否是目录(FILE_ATTRIBUTE_DIRECTORY是0x10,即16),32位表示是否是档案文件/目录(FILE_ATTRIBUTE_ARCHIVE是0x20,即32)……

 

那么怎么指定多个属性呢?因为每种属性写成二进制都只有一位是1,剩下的都是0,所以可以使用按位or运算符(|)指定多个属性,例如FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE,这样每种属性对应的位都为1,其余的为0。

 

至于判断是否具有某个属性,可以用按位and运算符(&)。例如对于属性attrib,判断是否是目录:attrib & FILE_ATTRIBUTE_DIRECTORY。如果不为0则是目录,为0则不是。

 

ftCreationTime

 

FILETIME结构。指定一个文件或目录的创建时间。如果文件系统不支持创建时间,此成员为0。

 

ftLastAccessTime

 

FILETIME结构。对于文件,指定文件最后被读取、写入,或(对于可执行文件)被运行的时间。对于目录,指定目录的创建时间。如果文件系统不支持最后一次写入时间,此成员为0。

 

ftLastWriteTime

 

FILETIME结构。对于文件,指定文件最后被写入、截短或重写的时间(例如调用WriteFile()或SetEndOfFile()时)。日期和时间在文件属性或描述符被改变时不会被更新。

 

nFileSizeHigh

 

DWORD。文件大小(以字节为单位)的高DWORD。除非文件大小大于MAXDWORD,否则值为0。文件大小等于(nFileSizeHigh * (MAXDWORD + 1)) + nFileSizeLow。

 

nFileSizeLow

 

DWORD。文件大小(以字节为单位)的低DWORD。

 

dwReserved0

 

DWORD。如果dwFileAttributes成员含有FILE_ATTRIBUTE_REPARSE_POINT属性,这个成员指定重新分析点标签(reparse point tag)。否则这个值是未定义的。

 

可能的值:

 

IO_REPARSE_TAG_CSV,IO_REPARSE_TAG_DEDUP,IO_REPARSE_TAG_DFS,IO_REPARSE_TAG_DFSR,IO_REPARSE_TAG_HSM,IO_REPARSE_TAG_HSM2,IO_REPARSE_TAG_MOUNT_POINT,IO_REPARSE_TAG_NFS,IO_REPARSE_TAG_SIS,IO_REPARSE_TAG_SIMLINK,IO_REPARSE_TAG_WIM。

 

dwReserved1

 

DWORD。保留给将来使用。

 

cFileName

 

CHAR/WCHAR数组,大小为MAX_PATH。文件名。

 

cAlternateFileName

 

CHAR/WCHAR数组,大小为14。文件的别名。名称的格式为8.3文件名格式。

 

FILETIME结构

 

可以看到WIN32_FIND_DATA的ftCreationTime、ftLastAccessTime、ftLastWriteTime类型是FILETIME结构。那么FILETIME结构是怎样的呢?下面是MSDN上的定义:

 

typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME;

 

dwLowDateTime

 

文件时间的低DWORD。

 

dwHighDateTime

 

文件时间的高DWORD。

 

FILETIME结构表示的时间(距离Epoch的秒数)为dwHighDateTime * (MAXDWORD + 1) + dwLowDateTime。

 

FindFirstFile()/FindNextFile()/FindClose()函数

 

要查找文件,需要使用FindFirstFile()、FindNextFile()和FindClose()函数。

 

FindFirstFile()函数

 

HANDLE WINAPI FindFirstFile( _In_ LPCTSTR lpFileName, _Out_ LPWIN32_FIND_DATA lpFindFileData );

 

搜索第一个文件,创建并返回搜索句柄。

 

lpFileName

 

CHAR/WCHAR指针(取决于是否定义UNICODE)。路径或文件名。可以包含通配符,例如*或?。不能以\\字符结尾。如果以通配符、.字符或目录名结尾,用户必须有根目录和所有子目录的访问权限。(遍历目录中的所有文件时,应以*.*结尾。)

 

lpFindFileData

 

WIN32_FIND_DATA指针。用于接收找到的文件/目录的信息。

 

返回值

 

如果成功,函数将创建一个搜索句柄,可以使用该句柄调用FindNextFile()和FindClose()。如果失败,返回INVALID_HANDLE_VALUE。

 

FindNextFile()函数

 

BOOL WINAPI FindNextFile( _In_ HANDLE hFindFile, _Out_ LPWIN32_FIND_DATA lpFindFileData );

 

搜索下一个文件。

 

hFindFile

 

HANDLE。搜索句柄。

 

lpFindFileData

 

WIN32_FIND_DATA指针。用于接收找到的文件/目录的信息。

 

返回值

 

如果成功,返回TRUE;如果失败(例如找不到更多的文件了或其它原因),返回FALSE。

 

FindClose()函数

 

BOOL WINAPI FindClose( _Inout_ HANDLE hFindFile );

 

释放搜索句柄。

 

hFindFile

 

HANDLE。搜索句柄。

 

返回值

 

如果成功,返回TRUE;如果失败,返回FALSE。

 

通配符(wildcards)

 

*和?字符被用作通配符。

 

指定全部具有某个扩展名的文件

 

格式为*.ext(ext为扩展名)。例如指定所有.txt文件:"*.txt"。指定D:\Projects\目录下所有.txt文件:"D:\\Projects\\*.txt"。

 

指定全部具有某个名称的文件/目录

 

格式为name.*(name为文件名)。例如指定所有名为readme(格式不限)的文件和目录:"readme.*"。指定D:\Projects\目录下的所有名为readme的文件:"D:\\Projects\\readme.*"。

 

指定具有一定长度的扩展名的文件

 

格式为name.???(name为文件名)。?的数量和扩展名长度一样。例如指定所有扩展名为4个字符,名为index的文件:"index.????"。

 

指定具有一定长度的文件名的文件

 

格式为???.ext(ext为扩展名)。?的数量和文件名的长度一样。例如指定所有扩展名为.txt,名字含有7个字符的文件:"???????.txt"。

 

当然还有更复杂的,例如*.???、????.*、*.*、????.???,分别是“所有扩展名长度为3的文件”、“所有文件名长度为4的文件/目录”、“所有文件/目录”、“所有文件名长度为4且扩展名长度为3的文件”。

 

当前目录和上一级目录

 

调用FindFirstFile()时,使用"."表示当前目录,使用".."表示上一级目录。FindFirstFile()和FindNextFile()所返回的文件/目录名也可能是"."或"..",可以忽略。

 

最后的工作

 

我们还需要声明一个HANDLE才能开始搜索:

 

HANDLE hFind;

 

程序示例

 

废话了这么久,也是该上程序代码了。

 

1. 遍历某个目录下的所有文件

 

遍历某个目录下的所有文件,并输出文件名和文件大小。

 

#include #include #include void listFiles(const char * dir); int main() { using namespace std; char dir[100]; cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3