FindFirstFile

基本概述:

FindFirstFileWindows API中用于启动一次文件 / 目录搜索的函数。它会在指定路径下查找第一个匹配条件的文件或目录,并返回一个搜索句柄(用于后续的FindNextFile调用),同时通过结构体返回该文件 / 目录的详细信息。
FindFirstFile 是一个宏,根据项目是否定义UNICODE宏,会映射到宽字符版本(FindFirstFileW)或ANSI版本(FindFirstFileA)。

基本语法

1
2
3
4
5
6
7
8
9
HANDLE FindFirstFileW(
[in] LPCWSTR lpFileName, //目录或路径以及文件名。 文件名可以包含通配符,例如(*)或(?)
[out] LPWIN32_FIND_DATAW lpFindFileData //指向存储找到的第一个文件/目录的详细信息的结构体指针
);

HANDLE FindFirstFileA(
[in] LPCSTR lpFileName,
[out] LPWIN32_FIND_DATAA lpFindFileData
);

lpFileName
表示要搜索的文件或目录路径,支持通配符*?
*:匹配任意长度的字符序列(如*.txt匹配所有后缀为.txt的文件)。
?:匹配单个字符(如file?.doc匹配file1.docfileA.doc等)。
路径格式:可以是绝对路径(如L"C:\\Users\\test\\*.pdf")或相对路径(如L".\\images\\*.*".表示当前目录)。

LPWIN32_FIND_DATAW

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct _WIN32_FIND_DATAW {
DWORD dwFileAttributes; //文件属性
FILETIME ftCreationTime; //创建时间
FILETIME ftLastAccessTime; //最后访问时间
FILETIME ftLastWriteTime; //最后修改时间
DWORD nFileSizeHigh; //文件大小高位(32位)
DWORD nFileSizeLow; //文件大小低位(32位)
DWORD dwReserved0; //保留字段
DWORD dwReserved1; //保留字段
_Field_z_ WCHAR cFileName[ MAX_PATH ];//主文件名(含扩展名)
_Field_z_ WCHAR cAlternateFileName[ 14 ];//8.3格式备用文件名
} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;

typedef struct _FILETIME {
DWORD dwLowDateTime; //时间值的低32位
DWORD dwHighDateTime; //时间值高32位
} FILETIME, *PFILETIME, *LPFILETIME;
FILETIME 本质是通过两个 32 位 DWORD 成员组合成一个 64 位整数 来表示时间。

WIN32_FIND_DATAW是文件搜索中 “信息载体” 的核心,通过其成员可获取文件的几乎所有基础属性:
判断类型(文件 / 目录)→ 用dwFileAttributes
获取文件名 → 用cFileName
处理文件大小 → 组合nFileSizeHighnFileSizeLow
跟踪文件变更 → 用ftLastWriteTime

返回值

成功:返回一个非零的搜索句柄(HANDLE类型),该句柄需传递给后续的FindNextFile使用。
失败:返回INVALID_HANDLE_VALUE(宏定义为 -1),需通过GetLastError()获取具体错误原因,常见错误:
ERROR_FILE_NOT_FOUND:未找到任何匹配的文件 / 目录。
ERROR_ACCESS_DENIED:无权限访问指定路径。
ERROR_PATH_NOT_FOUND:路径不存在。

FindNextFile

继续执行对 FindFirstFile、FindFirstFileEx或 FindFirstFileTransacted 函数的上一次调用的文件搜索。

基本语法

1
2
3
4
5
6
7
8
9
BOOL FindNextFileW(
[in] HANDLE hFindFile, //上一次调用 FindFirstFile 或 FindFirstFileEx 函数返回 的搜索句柄
[out] LPWIN32_FIND_DATAW lpFindFileData
);

BOOL FindNextFileA(
[in] HANDLE hFindFile,
[out] LPWIN32_FIND_DATAA lpFindFileData
);

基本示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <Windows.h>
#include <stdio.h>

// 打印文件属性的辅助函数
void PrintFileAttributes(DWORD attributes) {
printf("属性: ");
if (attributes & FILE_ATTRIBUTE_DIRECTORY) printf("目录 | ");
if (attributes & FILE_ATTRIBUTE_READONLY) printf("只读 | ");
if (attributes & FILE_ATTRIBUTE_HIDDEN) printf("隐藏 | ");
if (attributes & FILE_ATTRIBUTE_SYSTEM) printf("系统 | ");
if (attributes & FILE_ATTRIBUTE_ARCHIVE) printf("归档");
printf("\n");
}

int main() {
// 要遍历的目录路径(支持通配符,此处遍历当前目录下所有项)
LPCWSTR searchPath = L".\\*"; // .表示当前目录,*匹配所有文件/目录

// 存储文件信息的结构体
WIN32_FIND_DATAW findData;
ZeroMemory(&findData, sizeof(WIN32_FIND_DATAW)); // 初始化结构体

// 启动搜索,获取第一个文件/目录
HANDLE hFind = FindFirstFileW(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
printf("搜索失败!错误码: %d\n", GetLastError());
return 1;
}

printf("开始遍历目录: .\\\n");
printf("========================================\n");

// 循环遍历所有文件/目录
do {
// 过滤掉 "."(当前目录)和 ".."(父目录)
if (wcscmp(findData.cFileName, L".") == 0 ||
wcscmp(findData.cFileName, L"..") == 0) {
continue;
}

// 输出文件名(宽字符转多字节打印,兼容控制台)
wprintf(L"名称: %s\n", findData.cFileName);

// 输出文件类型和属性
PrintFileAttributes(findData.dwFileAttributes);

// 若为文件,输出大小(目录大小无意义)
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
LONGLONG fileSize = (LONGLONG)findData.nFileSizeHigh << 32 | findData.nFileSizeLow;
printf("大小: %lld 字节\n", fileSize);
}

printf("----------------------------------------\n");

} while (FindNextFileW(hFind, &findData)); // 获取下一个文件/目录

// 判断搜索结束原因(正常结束还是错误)
DWORD lastError = GetLastError();
if (lastError != ERROR_NO_MORE_FILES) {
printf("遍历过程出错!错误码: %d\n", lastError);
} else {
printf("遍历完成,无更多文件。\n");
}

// 关闭搜索句柄,释放资源
FindClose(hFind);

return 0;
}