程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++ Builder中目錄處理的一些函數

C++ Builder中目錄處理的一些函數

編輯:關於C++

在編程時,經常有一些針對目錄的操作,如打開目錄對話框選擇一個目錄,直接創建多級目錄,直接刪除多級目錄,判斷某個目錄是否存在等。本文就這些問題給出編程實現方法,並給出詳細的程序代碼,供各位編程愛好者參考。

一、判斷目錄是否存在:

C++ Builder中提供了檢查文件是否存在的函數FileExists,但沒有提供檢查目錄是否存在的函數,我們可以用Windows API函數FindFirstFile實現這個功能。程序實現如下:

設char *Dir為帶判斷的目錄

bool Exist;                      // 最後結果,表示目錄是否存在
if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0';  // 先刪除最後的“\”
WIN32_FIND_DATA wfd;                 // 查找
HANDLE hFind=FindFirstFile(Dir,&wfd);         
if(hFind==INVALID_HANDLE_VALUE)Exist=false;      // 沒有找到配備,目錄肯定不存在
else
{
   if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 檢查找到的結果是否目錄
     Exist=true;                   // 是目錄,目錄存在
   else
     Exist=false;                  // 是目錄,目錄不存在
   FindClose(hFind);
}

二、打開目錄選擇對話框選擇一個目錄:

大多專業軟件在要求輸入目錄的編輯框旁都放了一個按鈕,點擊後打開一個目錄窗口,很多編程愛好者也希望能掌握這個方法。實現這個功能要調用Windows API函數SHBrowseForFolder,完整聲明為WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(LPBROWSEINFO lpbi),返回一個ITEMIDLIST類型的指針,通過這個指針調用函數SHGetPathFromIDList可以確定所選擇的目錄的全名稱。入參為BROWSEINFO結構的指針,這個結構較為復雜,成員如下所示:

HWND hwndOwner;    // 擁有對話框的窗口,可以設置為Application->Handle

LPCITEMIDLIST pidlRoot; // ITEMIDLIST類型的指針,表示在哪個路徑下選擇,一般可以設置為NULL

LPSTR pszDisplayName; // 選擇後,所選目錄的名稱(不包含父級目錄)被拷貝到這個指針指向的位置

LPCSTR lpszTitle;   // 作為標題顯示在對話框中目錄樹的上面,可以根據實際情況設置

UINT ulFlags;     // 標志位,有點復雜,一般設置為BIF_RETURNONLYFSDIRS

BFFCALLBACK lpfn;   // 回調函數,一般不用,設置為NULL

LPARAM lParam;     // 預定義的對話框傳遞給回調函數的值

int iImage;      // 與所選目錄相關聯的圖標在系統圖標集合中的索引

可以看出,使用函數SHBrowseForFolder還真麻煩,普通愛好者掌握它確實有一定的難度,現給出完整程序段如下:

#include <shlobj.h>          // 必須包含的頭文件
char SelectedDir[MAX_PATH];       // 最終結果
BROWSEINFO bi;             // 入參
char FolderName[MAX_PATH];       // 所選目錄名稱,例如選擇C:\Windows\Font,則為Font
LPITEMIDLIST ItemID;          // 所選目錄的系統標志指針
memset(SelectedDir, 0, MAX_PATH);       // 初始化最終結果
memset(&bi, 0, sizeof(BROWSEINFO));  // 初始化入參所有數據
bi.hwndOwner = Application->Handle;
bi.pszDisplayName = FolderName;
bi.lpszTitle = "請選擇目錄";      // 改成自己希望的
bi.ulFlags=BIF_RETURNONLYFSDIRS;
ItemID = SHBrowseForFolder(&bi);   // 調用函數,打開目錄選擇對話框
if(ItemID)
{
   SHGetPathFromIDList(ItemID, SelectedDir);   // 獲取所選目錄的全名
   GlobalFree(ItemID);           // 返回的ItemID占用了系統資源,不要忘了釋放
}

三、直接建立多級目錄:

Windows API提供了建立目錄的函數CreateDirectory,但是調用前要保證父目錄必須存在,否則會失敗。其實,有時越級建立多級目錄很有用,因為在建立目錄特別是建立多層目錄時,層層加以判斷會大大地增加程序的復雜程度。如何實現這個功能呢?本人用遞歸方法設計了一個可以直接建立多級目錄的函數,現說明如下,供各位朋友參考。

bool MakeDirectoryEx(const AnsiString &P) // 入參為打算創建的目錄名,根據操作結果返回"true"或"false"
{
   if(P.IsEmpty())return false;
   int len=P.Length();
   char *Path=P.c_str();
   if(Path[len-1]=='\\')
   {
     len--;
     Path[len]='\0';
   }                   // 刪除末尾的"\"
   AnsiString Dir=Path;
   // 分開父目錄和本身目錄名稱
   AnsiString Parent;
   for(int i=len-1;i>0;i--)
   {
     if(Dir.IsPathDelimiter(i))
     {
       Parent=Dir.SubString(0,i);
       break;
     }
   }
   if(Parent.IsEmpty())return false; // 目錄名稱錯誤
   bool Ret=true;
   if(Parent.Length()>3)     // 如果長度小於3,表示為磁盤根目錄
     Ret=DirectoryExistEx(Parent.c_str());// 檢查父目錄是否存在
   if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目錄不存在,遞歸調用創建父目錄
   if(Ret)                    // 父目錄存在,直接創建目錄
   {
     SECURITY_ATTRIBUTES sa;
     sa.nLength=sizeof(SECURITY_ATTRIBUTES);
     sa.lpSecurityDescriptor=NULL;
     sa.bInheritHandle=0;
     Ret=CreateDirectory(Path,&sa);
   }
   return Ret;
}

可以看出基本方法是:

先檢查父目錄是否存在,這裡用到的函數DirectoryExistEx可以按照前面介紹的方法設計;

如果父目錄存在,則直接創建目錄,否則自我調用創建父目錄。

四、直接刪除整個目錄:

在DOS下有一個Deltree命令,用來刪除整個目錄,這是一個很有用的功能,可惜,Windows API提供的函數RemoveDirectory只能刪除控目錄,就像DOS的RD命令一樣。編程實現這個功能同樣需要遞歸方法,基本流程是:

查找目錄下的所有文件和目錄,即調用API函數FindFirstFile、FindNextFile(*.*)

如果找到文件,則強制刪除。所謂強制刪除,即刪除前先調用SetFileAttributes把它的屬性設置為Normal,然後調用DeleteFile刪除它。

如果找到目錄,則進行自我調用,即開始遞歸過程。

如果沒有找到目錄,即表示為控目錄,調用RemoveDirectory直接刪除。

具體程序代碼如下:

bool DeleteDirectoryEx(const AnsiString &P)
{
   if(P.IsEmpty() || P.Length()<4)return false;    // 參數長度必須大於3,即不能為磁盤根目錄或空白
   int len=P.Length();
   char *Path=P.c_str();
   AnsiString Dir=Path;
   if(Path[len-1]!='\\')Dir=Dir+'\\';
   AnsiString Files=Dir+"*.*";
   WIN32_FIND_DATA wfd;
   HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);
   bool Ret=true;
   AnsiString Tmp;
   if(hFind!=INVALID_HANDLE_VALUE)
   {
     bool bFind=true;
     while(bFind)
     {
       if(wfd.cFileName[0]!='.') // . ..
       {
         Tmp=Dir+wfd.cFileName;
         if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
         { // 刪除所有子目錄
           Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);
         }else
         { // 刪除所有文件
           SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);
           Ret=Ret&&DeleteFile(Tmp.c_str());
         }
       }
       bFind=FindNextFile(hFind,&wfd);
     }
     FindClose(hFind);
   }
   if(Ret)return RemoveDirectory(Path);
   return false;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved