C语言如何使用findFirstFile函数?

99ANYc3cd6
预计阅读时长 20 分钟
位置: 首页 C语言 正文

FindFirstFile 是 Windows API 的一部分,它用于在文件系统中查找与指定文件名(可以包含通配符,如 和 )匹配的第一个文件或目录,要找到后续匹配的文件,你需要配合使用 FindNextFile 函数,当查找完成后,必须调用 FindClose 来释放资源。


函数原型与所需头文件

在使用之前,你需要包含以下头文件:

#include <windows.h>   // 包含 FindFirstFile, FindNextFile, FindClose 等
#include <tchar.h>     // 包含 TCHAR 及相关字符串处理函数
#include <stdio.h>     // 用于标准输入输出,如 printf

函数原型:

HANDLE FindFirstFile(
  [in]           LPCTSTR           lpFileName,
  [out]          LPWIN32_FIND_DATA lpFindFileData
);

参数说明:

  • lpFileName (输入): 一个指向以空结尾的字符串的指针,用于指定要查找的文件名。
    • 可以包含通配符 (匹配零个或多个字符) 和 (匹配单个字符)。
    • 可以包含相对路径或绝对路径。
      • C:\\MyData\\*.txt (查找 C 盘 MyData 目录下所有 .txt 文件)
      • *.c (在当前工作目录下查找所有 .c 文件)
      • ..\\..\\images\\*.png (查找上级目录的 images 文件夹中的所有 png 文件)
  • lpFindFileData (输出): 一个指向 WIN32_FIND_DATA 结构体指针,如果函数成功,这个结构体将被填充找到的第一个文件或目录的详细信息。

返回值:

  • 成功: 返回一个有效的搜索句柄 ( HANDLE ),这个句柄将用于后续的 FindNextFile 调用。
  • 失败: 返回 INVALID_HANDLE_VALUE,要获取具体的错误信息,可以调用 GetLastError()

核心数据结构: WIN32_FIND_DATA

这个结构体是理解 FindFirstFile 的关键,它包含了找到的文件或目录的所有元数据。

typedef struct _WIN32_FIND_DATA {
  DWORD    dwFileAttributes; // 文件属性 (如只读、隐藏、目录等)
  FILETIME ftCreationTime;   // 创建时间
  FILETIME ftLastAccessTime; // 最后访问时间
  FILETIME ftLastWriteTime;  // 最后修改时间
  DWORD    nFileSizeHigh;    // 文件大小 (高位)
  DWORD    nFileSizeLow;     // 文件大小 (低位)
  DWORD    dwReserved0;      // 保留
  DWORD    dwReserved1;      // 保留
  TCHAR    cFileName[MAX_PATH]; // 文件名或目录名
  TCHAR    cAlternateFileName[14]; // 8.3 格式的短文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;

重要成员解释:

  • dwFileAttributes: 文件属性,可以通过位掩码来测试,常用值有:
    • FILE_ATTRIBUTE_DIRECTORY: 如果这是一个目录,则设置此位。
    • FILE_ATTRIBUTE_ARCHIVE: 存档文件。
    • FILE_ATTRIBUTE_HIDDEN: 隐藏文件。
    • FILE_ATTRIBUTE_READONLY: 只读文件。
  • nFileSizeHighnFileSizeLow: 由于文件大小可能超过 32 位 DWORD 的最大值,所以用两个 DWORD 组合成一个 64 位的整数,要获取完整的文件大小,你需要将它们合并。
  • cFileName: 找到的文件或目录的名称。

完整示例代码

下面是一个完整的示例,演示如何查找当前目录下所有的 .c 文件,并打印它们的名称、大小和属性。

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[]) {
    // 1. 准备要查找的文件名
    // _T("*.c") 是一个通配符,表示查找所有以 .c 结尾的文件
    // TCHAR 类型支持 Unicode 和 ANSI,更具可移植性
    TCHAR* szFile = _T("*.c");
    // 2. 定义 WIN32_FIND_DATA 结构体变量
    WIN32_FIND_DATA FindFileData;
    // 3. 调用 FindFirstFile 开始查找
    // INVALID_HANDLE_VALUE 是一个宏,表示无效句柄
    HANDLE hFind = FindFirstFile(szFile, &FindFileData);
    // 4. 检查查找是否成功
    if (hFind == INVALID_HANDLE_VALUE) {
        // 如果失败,打印错误信息
        _tprintf(_T("FindFirstFile failed (%d)\n"), GetLastError());
        return 1;
    }
    // 5. 循环遍历所有匹配的文件
    // FindFirstFile 找到第一个匹配项后,循环体内部用 FindNextFile 找后续的
    _tprintf(_T("Found files matching '%s':\n\n"), szFile);
    do {
        // 打印文件名
        _tprintf(_T("File Name: %s\n"), FindFileData.cFileName);
        // 判断是文件还是目录
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            _tprintf(_T("  Type: Directory\n"));
        } else {
            _tprintf(_T("  Type: File\n"));
            // 计算并打印文件大小 (合并高32位和低32位)
            LARGE_INTEGER fileSize;
            fileSize.LowPart = FindFileData.nFileSizeLow;
            fileSize.HighPart = FindFileData.nFileSizeHigh;
            _tprintf(_T("  Size: %lld bytes\n"), fileSize.QuadPart);
        }
        // 打印文件属性 (简化版)
        _tprintf(_T("  Attributes: "));
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) _tprintf(_T("Archive "));
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) _tprintf(_T("Hidden "));
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) _tprintf(_T("ReadOnly "));
        _tprintf(_T("\n\n"));
    } while (FindNextFile(hFind, &FindFileData) != 0); // 只要 FindNextFile 返回非0,就继续循环
    // 6. 检查循环是否因为找到所有文件而正常结束,还是因为发生错误
    // FindNextFile 失败,需要用 GetLastError 判断原因
    if (GetLastError() != ERROR_NO_MORE_FILES) {
        _tprintf(_T("FindNextFile failed (%d)\n"), GetLastError());
        FindClose(hFind); // 发生错误也要关闭句柄
        return 1;
    }
    // 7. 查找完成,关闭句柄,释放资源
    FindClose(hFind);
    _tprintf(_T("Search completed.\n"));
    return 0;
}

关键步骤总结

  1. 包含头文件: #include <windows.h> 是必须的。
  2. 构造搜索路径: 准备一个包含通配符的字符串,如 C:\\temp\\*
  3. 声明结构体: 创建一个 WIN32_FIND_DATA 类型的变量。
  4. 开始搜索: 调用 FindFirstFile,传入搜索路径和结构体地址,检查返回值是否为 INVALID_HANDLE_VALUE
  5. 处理结果: 如果成功,WIN32_FIND_DATA 结构体中就有了第一个文件的信息。
  6. 循环查找: 使用 do-while 循环和 FindNextFile 来获取所有后续匹配的文件。FindNextFile 同样需要检查返回值。
  7. 释放资源: 当查找结束后(无论是正常结束还是中途出错),必须调用 FindClose(hFind) 来关闭搜索句柄,防止资源泄漏。

重要注意事项

  • 资源释放: FindClose 非常重要,忘记调用它会导致句柄泄漏,长时间运行的程序可能会因此耗尽系统资源。
  • 和 目录: 当你使用 作为搜索模式( 或 C:\\*)时,FindFirstFile 会返回两个特殊的目录:
    • 代表当前目录。
    • 代表父目录。 在你的代码中,需要明确处理这两种情况,通常选择跳过它们。
  • 错误处理: FindFirstFileFindNextFile 都可能失败,除了检查它们的返回值,调用 GetLastError() 可以获取更详细的错误代码,有助于调试。
  • 跨平台性: FindFirstFileWindows 特有的 API,如果你需要编写跨平台的 C 代码(例如在 Linux 或 macOS 上也能运行),应该使用标准 C 库中的函数,如 opendir, readdir, closedir (POSIX 标准)。
  • 路径分隔符: 在 Windows 中,路径分隔符可以是反斜杠 \,但在 C 字符串中 \ 是转义字符,为了方便,可以使用双反斜杠 \\,或者使用正斜杠 ,现代 Windows API 也完全支持正斜杠作为路径分隔符,使用 _T() 宏和 TCHAR 类型可以更好地处理 Unicode 字符串路径。
-- 展开阅读全文 --
头像
织梦dsql如何获取数据库10条数据?
« 上一篇 12-11
C语言初始化有哪些关键点?
下一篇 » 12-11

相关文章

取消
微信二维码
支付宝二维码

目录[+]