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

C++Builder 遞歸遍歷檔案系統建構目錄樹:TTreeView + TListView 完整實作

     編輯:VC 教學

前言

利用 TTreeView 顯示目錄階層、TListView 顯示檔案清單,是檔案管理器的經典 UI 模式。本文提供完整的 C++Builder 實作:遞歸掃描磁碟機建構樹狀結構、節點點擊動態載入檔案清單、圖示關聯與日期格式化。

核心資料結構與變數


TTreeNode* currNode;      // 遞歸過程中暫存當前父節點
int DirCount, FileCount, DriveCount;

遞歸掃描目錄樹:TreeInit


void TForm1::TreeInit(String path, TTreeNode* myNode)
{
    TSearchRec sr;
    // FindFirst 返回 0 表成功
    if (FindFirst(path + "\\*.*", faAnyFile, sr) == 0)
    {
        do
        {
            // 只處理目錄,跳過 "." ".."
            if ((sr.Attr & faDirectory) == faDirectory)
            {
                if (sr.Name != "." && sr.Name != "..")
                {
                    currNode = TreeView1->Items->AddChild(myNode, sr.Name);
                    TreeInit(path + "\\" + sr.Name, currNode); // 遞歸
                    DirCount++;
                }
            }
            // 檔案不在樹中顯示,由 ListView 處理
        }
        while (FindNext(sr) == 0);
        FindClose(sr); // 必須關閉搜尋控制代碼
    }
}

表單建立:掛載磁碟機根節點


void __fastcall TForm1::FormCreate(TObject *Sender)
{
    String Drive, path;
    DirCount = FileCount = 0;
    DriveCount = DriveComboBox1->Items->Count;

    TreeView1->Items->BeginUpdate(); // 凍結 UI 更新,大幅提升效能
    TreeView1->Items->Clear();

    // 根節點:「我的電腦」
    currNode = TreeView1->Items->Add(TreeView1->Selected, "我的電腦");
    currNode->Selected = true;

    // 遍歷 DriveComboBox 取得所有磁碟機
    for (int i = 0; i < DriveCount; i++)
    {
        Drive = DriveComboBox1->Items->Strings[i].SubString(1, 1); // 取得 "C" "D" ...
        path = Drive + ":";
        currNode = TreeView1->Items->AddChild(TreeView1->Selected,
            DriveComboBox1->Items->Strings[i]); // 顯示完整磁碟機名稱
        TreeInit(path, currNode); // 遞歸掃描該磁碟機
    }
    TreeView1->Items->EndUpdate(); // 解除凍結,一次性重繪
}

樹節點點擊:動態載入檔案清單至 ListView


void __fastcall TForm1::TreeView1Click(TObject *Sender)
{
    TTreeNode* node = TreeView1->Selected;
    String path;

    // 1. 由節點向上遞迴組合完整路徑
    if (node->Level > 0) // 非根節點
    {
        do
        {
            if (node->Level == 1) // 磁碟機節點:文字如 "C: [標籤]"
                path = node->Text.SubString(1, 2) + (path.IsEmpty() ? "" : "\\") + path;
            else
                path = node->Text + (path.IsEmpty() ? "" : "\\") + path;
            node = node->Parent;
        }
        while (node->Level > 0);
    }
    else
    {
        // 點擊根節點「我的電腦」:顯示磁碟機清單
        ListView1->Items->BeginUpdate();
        ListView1->Items->Clear();
        for (int i = 0; i < TreeView1->Selected->Count; i++)
        {
            TListItem* li = ListView1->Items->Add();
            li->Caption = TreeView1->Selected->Item[i]->Text;
        }
        ListView1->Items->EndUpdate();
        return;
    }

    // 2. 掃描路徑下檔案填充 ListView
    ListView1->Items->BeginUpdate();
    ListView1->Items->Clear();

    TSearchRec sr;
    if (FindFirst(path + "\\*.*", faAnyFile, sr) == 0)
    {
        do
        {
            if (sr.Name != "." && sr.Name != "..")
            {
                TListItem* li = ListView1->Items->Add();
                li->Caption = sr.Name;

                if (sr.Attr == faDirectory)
                {
                    li->SubItems->Add("");           // 大小欄留白
                    li->SubItems->Add("資料夾");      // 類型欄
                }
                else
                {
                    li->SubItems->Add(IntToStr(sr.Size)); // 大小
                    li->SubItems->Add("檔案");           // 類型
                }
                // 日期時間格式化
                li->SubItems->Add(FileDateToDateTime(sr.Time).DateTimeString());
            }
        }
        while (FindNext(sr) == 0);
        FindClose(sr);
    }

    ListView1->AlphaSort(); // 依名稱排序
    ListView1->Items->EndUpdate();
}

關鍵技術點總結

技術用途備註
TDriveComboBox自動列舉系統磁碟機無需手動 GetLogicalDrives
BeginUpdate/EndUpdate凍結/解除 UI 重繪大量節點/項目操作時必加,否則極慢
FindFirst/FindNext/FindCloseVCL 封裝 FindFirstFile 等 API跨平台相容,自動處理 ANSI/Unicode
TSearchRec.Attr檔案屬性位元組faDirectory, faHidden, faSysFile, faReadOnly 等
FileDateToDateTimeDOS 日期時間轉 TDateTime再用 DateTimeString() 格式化顯示
AlphaSortListView 依 Caption 字母排序報表模式可用 CustomSort 自訂比較

效能優化建議

  • 虛擬模式:ListView1->OwnerData = true,處理 OnData 事件按需提供資料,支援百萬級項目。
  • 背景執行緒掃描:大型磁碟機掃描會阻塞 UI,移至 TThread 執行,完成後 Synchronize 更新 TreeView。
  • 圖示快取:使用 SHGetFileInfo + SHGFI_SYSICONINDEX 取得系統圖示索引,避免重複提取 HICON。
  • 延遲載入:樹節點展開時 (OnExpanding) 再掃描子目錄,而非啟動時全掃。

常見問題排查

這套 TTreeView + TListView + 遞歸 FindFirst 的架構,是 C++Builder 開發檔案管理類應用的標準範本,掌握後可輕鬆擴充為多欄位報表、縮圖預覽、檔案搜尋等進階功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
現象原因解決
樹節點重複/無限遞歸未正確過濾 "." ".." 或符號連結加入 sr.Name != "." && sr.Name != "..",檢查 faSymLink
ListView 不顯示檔案路徑組合錯誤(雙反斜線、缺少磁碟機代號)除錯輸出 path 變數,確認格式 "C:\\Folder\\Sub"
日期顯示 1601/1/1FileDateToDateTime 失敗(sr.Time 為 0 或無效)檢查 FindFirst 返回值,確認 sr.Time 有效
網路磁碟機掃描卡死同步阻塞、逾時無回應移至背景執行緒,設定網路逾時