首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MFC 遍歷目錄與文件:CFileFind 實戰完整指南

     編輯:關於C語言

界面佈局與控制項變數

控制項類型ID變數名說明
主目錄ComboBoxIDC_MAIN_DIRm_cbMainDir下拉列表顯示常用根目錄
子目錄ListBoxIDC_SUB_DIRSm_lbSubDirs列出當前目錄下的子目錄
所有文件ListBoxIDC_LIST_ALL_FILESm_lbAllFiles列出當前目錄下的文件(含隱藏/系統/只讀)

初始化常用根目錄


BOOL CMyDialog::OnInitDialog() {
    CDialogEx::OnInitDialog();

    char szBuf[MAX_PATH];
    m_cbMainDir.AddString(_T("C:\\"));
    GetWindowsDirectory(szBuf, MAX_PATH);     m_cbMainDir.AddString(szBuf);
    szBuf[2] = '\0';                          m_cbMainDir.AddString(szBuf); // 根目錄 C:\
    GetSystemDirectory(szBuf, MAX_PATH);      m_cbMainDir.AddString(szBuf);
    GetCurrentDirectory(MAX_PATH, szBuf);     m_cbMainDir.AddString(szBuf);

    return TRUE;
}

核心:響應 ComboBox 選擇變更,枚舉目錄與文件


void CMyDialog::OnCbnSelchangeMainDir() {
    CString strDir, strPath;
    int nSel = m_cbMainDir.GetCurSel();
    if (nSel == CB_ERR) return;

    m_cbMainDir.GetLBText(nSel, strDir);
    m_lbSubDirs.ResetContent();
    m_lbAllFiles.ResetContent();

    strPath = strDir + _T("\\*.*");

    CFileFind finder;
    BOOL bWorking = finder.FindFile(strPath);
    while (bWorking) {
        bWorking = finder.FindNextFile();
        if (finder.IsDots()) continue; // 忽略 "." 與 ".."

        if (finder.IsDirectory()) {
            m_lbSubDirs.AddString(finder.GetFileName());
        } else {
            // 文件:檔案屬性位元組合判斷
            DWORD attr = finder.GetFileAttributes();
            if (attr & FILE_ATTRIBUTE_ARCHIVE ||
                attr & FILE_ATTRIBUTE_HIDDEN ||
                attr & FILE_ATTRIBUTE_READONLY ||
                attr & FILE_ATTRIBUTE_SYSTEM) {
                m_lbAllFiles.AddString(finder.GetFileName());
            }
        }
    }
    finder.Close();
}

文件屬性位元組合判斷詳解

WIN32_FIND_DATA::dwFileAttributes 為位元組合,常見常數(winnt.h):

常數值含義
FILE_ATTRIBUTE_READONLY0x00000001唯讀
FILE_ATTRIBUTE_HIDDEN0x00000002隱藏
FILE_ATTRIBUTE_SYSTEM0x00000004系統檔案
FILE_ATTRIBUTE_DIRECTORY0x00000010目錄
FILE_ATTRIBUTE_ARCHIVE0x00000020存檔標記(備份工具使用)
FILE_ATTRIBUTE_NORMAL0x00000080標準檔案(無其他屬性)
FILE_ATTRIBUTE_TEMPORARY0x00000100暫存檔案
FILE_ATTRIBUTE_COMPRESSED0x00000800壓縮
FILE_ATTRIBUTE_ENCRYPTED0x00004000加密 (EFS)

正確判斷目錄:(attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY
正確判斷一般文件:(attr & FILE_ATTRIBUTE_DIRECTORY) == 0

遞歸遍歷整棵目錄樹(補充)


void EnumAll(const CString& path, CStringArray& dirs, CStringArray& files) {
    CFileFind finder;
    CString spec = path + _T("\\*.*");
    BOOL b = finder.FindFile(spec);
    while (b) {
        b = finder.FindNextFile();
        if (finder.IsDots()) continue;
        if (finder.IsDirectory()) {
            dirs.Add(finder.GetFilePath());
            EnumAll(finder.GetFilePath(), dirs, files); // 遞歸
        } else {
            files.Add(finder.GetFilePath());
        }
    }
    finder.Close();
}

常見坑點與最佳實踐

  1. FindFile/FindNextFile 成對使用,最後必須 Close() 釋放句柄。
  2. IsDots() 必須過濾,否則遞歸會陷入無限循環。
  3. 屬性判斷用位運算,切勿用 == 比較完整值(一個文件通常同時擁有多個屬性)。
  4. Unicode 建構下,CString、CFileFind 皆支援寬字元,無需手動轉碼。
  5. 大量文件時,ListBox 會極其卡頓;建議改用 CListCtrl (Report 模式) + 虛擬模式 或 分頁載入。

總結

MFC CFileFind 封裝了 FindFirstFile/FindNextFile,配合位元屬性判斷,能輕鬆實現目錄/文件枚舉、遞歸遍歷與屬性過濾。掌握位元組合邏輯與資源釋放時機,是編寫健壯文件操作代碼的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved