QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 4391|回复: 0
打印 上一主题 下一主题

目录处理函数

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2005-1-26 13:18 |只看该作者 |倒序浏览
|招呼Ta 关注Ta

目录处理函数

R1 c; o g+ R6 W

编程语言:C++ Builder 作者:王行舟

/ E ]' t4 j: I+ g9 b" E

在编程时,经常有一些针对目录的操作,如打开目录对话框选择一个目录,直接创建多级目录,直接删除多级目录,判断某个目录是否存在等。本文就这些问题给出编程实现方法,并给出详细的程序代码,供各位编程爱好者参考。

5 S! z R+ w1 B1 ^. A) R

一、判断目录是否存在:

7 N. g1 o: w2 O2 v4 k

C++ Builder中提供了检查文件是否存在的函数FileExists,但没有提供检查目录是否存在的函数,我们可以用Windows API函数FindFirstFile实现这个功能。程序实现如下:

9 R- }# L8 W7 S9 q$ Y9 m

设char *Dir为带判断的目录; ?7 g9 ]2 ~ |+ Y4 J bool Exist; // 最后结果,表示目录是否存在4 p) e+ C, m( b8 D% e5 O/ c if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” + S! x; P0 l6 O% n9 fWIN32_FIND_DATA wfd; // 查找2 n9 d5 r# ? ~" S8 Q% w! q HANDLE hFind=FindFirstFile(Dir,&wfd); h# t9 a- i5 g; Pif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 4 {1 v) L, @ [2 Oelse 6 K7 t; r/ J7 a. h9 @, p( e( F{ 3 B2 S6 F$ W) f" ~7 G if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录# T1 u# ]% F) Z) l# g/ q' x/ r Exist=true; // 是目录,目录存在 ' c m' B" q3 T% T$ E else 7 l" _! W* w1 v. e0 U) n+ h Exist=false; // 是目录,目录不存在 ( o7 T: F) P7 U0 H6 S FindClose(hFind); * j/ Z. a9 D1 B! k0 m}

, S9 k1 D" q( F" ~

二、打开目录选择对话框选择一个目录:

: k/ ]& U6 N- H) P. k' `

大多专业软件在要求输入目录的编辑框旁都放了一个按钮,点击后打开一个目录窗口,很多编程爱好者也希望能掌握这个方法。实现这个功能要调用Windows API函数SHBrowseForFolder,完整声明为WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(LPBROWSEINFO lpbi),返回一个ITEMIDLIST类型的指针,通过这个指针调用函数SHGetPathFromIDList可以确定所选择的目录的全名称。入参为BROWSEINFO结构的指针,这个结构较为复杂,成员如下所示:

- C% H' i4 H) q; z$ X$ e

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 0 ?7 K% j0 b% j6 V$ z3 | LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL; s3 z& Z$ ]8 R1 j5 g2 { LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 / m/ U% `1 i2 J8 X5 l% ?$ DLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 4 g. {) R j6 o7 p) L UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS ( a% m2 y% @) m8 V9 F5 Q3 a BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL : H6 y W9 C: d2 gLPARAM lParam; // 预定义的对话框传递给回调函数的值, v! x# `: Z: N6 N& A4 v6 Z int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 ; m9 v$ Q' x1 E# q+ x! I可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: ! ?; V- q1 Q% C7 l4 ^#include <shlobj.h> // 必须包含的头文件 % \- a" @" a- c$ R# r3 p2 w. k7 Xchar SelectedDir[MAX_PATH]; // 最终结果 8 f" I, K' `% i5 d5 ZBROWSEINFO bi; // 入参 % g( d: j. z% `7 G ?# zchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font - r) _9 L) y: [) k3 z* c LPITEMIDLIST ItemID; // 所选目录的系统标志指针

( L0 g' ^: v5 t$ h- v

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 - J0 X3 A9 f, ~2 e% S3 b/ kmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据6 `& w- J$ l/ Q3 z$ C* c* f: z bi.hwndOwner = Application->Handle; 8 z- U% W7 p4 l" P/ Z$ dbi.pszDisplayName = FolderName; / o4 w) |7 c8 Xbi.lpszTitle = "请选择目录"; // 改成自己希望的 7 x, B! ]9 I, w+ ?bi.ulFlags=BIF_RETURNONLYFSDIRS;& H; @8 ]1 n1 I9 o ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 % ]$ j/ i+ }# ?: p% R3 Wif(ItemID). F& P7 M( f' W0 Y& k$ ]8 m {1 b3 ?1 C) `' y3 L SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 7 b, {& i9 J* @, q4 H1 \- c$ x GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放0 T; _; Y' m# A# p# X1 U }

& f" `( Y$ Y2 Z: `

三、直接建立多级目录:

- } m* W& }9 H4 v

Windows API提供了建立目录的函数CreateDirectory,但是调用前要保证父目录必须存在,否则会失败。其实,有时越级建立多级目录很有用,因为在建立目录特别是建立多层目录时,层层加以判断会大大地增加程序的复杂程度。如何实现这个功能呢?本人用递归方法设计了一个可以直接建立多级目录的函数,现说明如下,供各位朋友参考。

3 V3 W, U- G9 J) q

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false". H1 w* `4 o" ^* [3 R# { { * @& U2 @( z; {& p- f& O4 W! p if(P.IsEmpty())return false;! X, w6 o; Y- q int len=P.Length();1 {: X) A* K$ j" W$ b. o# e) \ char *Path=P.c_str(); ' g1 r& l* p: h; @ T, o* i if(Path[len-1]=='\\')! H! e% P2 d r, f9 ^; t { 4 i) l( G: o( t0 R: x/ y3 @ len--; " o( l) V y# X$ Y& j8 R Path[len]='\0';' p: k6 C' k1 ? } // 删除末尾的"\"$ X, |! T9 R+ | AnsiString Dir=Path;; ^7 i ^; r, W% ?3 ?$ i6 c( ^ // 分开父目录和本身目录名称 2 v2 i" B- @3 `) a& K1 v AnsiString Parent;; _! W4 s1 F0 \. e. c, A for(int i=len-1;i>0;i--) / m6 e2 I6 [7 F/ x3 X { " i1 r! v4 {; I, O& A& o if(Dir.IsPathDelimiter(i)) 9 C' B. U8 D0 m {& q- \$ _. G9 J- I) g7 { Parent=Dir.SubString(0,i); - o6 z( J9 Q5 F$ m! P3 m break;8 j; d2 H6 X! @' k; w# f } ) h' ]+ x, q- R) g& i } 8 r" h' F) p5 { if(Parent.IsEmpty())return false; // 目录名称错误 " _5 J; R3 ^" ~* b bool Ret=true;4 d! V" m4 C" @ if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录$ }- V% H$ R9 s2 c/ }. B Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 t& R+ f d. h4 V4 T if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录( H% |1 _- k7 J/ ?9 | if(Ret) // 父目录存在,直接创建目录+ W, V" u5 X2 L8 @* [ { / J( [; l' g* t: V1 u2 a& k( ^* @ SECURITY_ATTRIBUTES sa;! C2 A% `* z9 x$ {* T sa.nLength=sizeof(SECURITY_ATTRIBUTES); 1 q8 B$ b" r+ c7 B% E/ n sa.lpSecurityDescriptor=NULL;; \+ z, g/ Q9 `' Y4 D sa.bInheritHandle=0;6 e. G; |3 B+ u3 [5 f5 N Ret=CreateDirectory(Path,&sa); ; [% c' {$ p3 e3 I; z* K" s }0 H1 P s- C- d* q return Ret;. \) \6 m0 `. {/ ^ } / P) z! N! g7 n5 o' D; n 可以看出基本方法是: . s% X* W/ s( B2 y; D先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; 5 t: j) @1 f$ X( q4 d2 O如果父目录存在,则直接创建目录,否则自我调用创建父目录。

* x5 }* v1 s$ J; {) x

3 s9 {- A6 e5 {& v$ _: C* x 四、直接删除整个目录:

' r- r+ z/ V/ f& K# D" s

在DOS下有一个Deltree命令,用来删除整个目录,这是一个很有用的功能,可惜,Windows API提供的函数RemoveDirectory只能删除控目录,就像DOS的RD命令一样。编程实现这个功能同样需要递归方法,基本流程是:

8 R* J% w1 S. j

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 4 _" \0 l, G! W1 b) O 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 , R2 m( K% U( I8 ]4 ?如果找到目录,则进行自我调用,即开始递归过程。 ) d4 r H( O, G7 C 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 ' ]- n4 t( X3 U, S: z& @, g具体程序代码如下:

* N0 p4 R/ Y* Q% ^

bool DeleteDirectoryEx(const AnsiString &)( G2 k1 i R- y- v8 {9 H& ` { . m# s* q3 ]8 S$ L% w. Q if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白0 p1 l; J% x0 `/ P int len=P.Length(); % \2 z* O3 ~/ w+ A* [/ S; q char *Path=P.c_str(); F4 ]% q r# }' t6 F AnsiString Dir=Path;: ?; F- }7 c0 x if(Path[len-1]!='\\')Dir=Dir+'\\';+ C. h+ N9 t6 T q9 Z( ^' w9 H AnsiString Files=Dir+"*.*"; 4 z, i4 S1 ~5 U3 Q/ z WIN32_FIND_DATA wfd;/ K8 _, L% h3 D1 F9 h HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);' X# V1 O, ]# p; s7 S+ f& |7 ^) _ bool Ret=true; 1 m. v8 |0 ]2 C AnsiString Tmp;" o* \% f Q" g, B4 ` if(hFind!=INVALID_HANDLE_VALUE) . t# o9 q8 A' K/ F5 _ { $ [" W2 w7 V5 n- C+ w0 A bool bFind=true;8 `% w, h( P( f0 @' f9 C while(bFind)# X' ~6 m6 f( w! i { 7 |4 S" w4 E/ z if(wfd.cFileName[0]!='.') // . ../ u* c5 \# c7 v( \. I0 F {7 {6 S: t" h7 |4 J! t+ ]9 o( ] Tmp=Dir+wfd.cFileName;. ], T/ ?$ ~# W/ y& ^- y: G9 {) T4 s if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) % ^* O' F% I( | { // 删除所有子目录 6 H( [' [2 _3 R$ t. O' q5 M! _8 K2 r U3 o Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); 4 t2 G5 s/ k5 E! u% p- J }else1 l0 ^2 }% ~5 \. E d9 c' I$ ~ { // 删除所有文件 ) t( }0 g6 V) C0 l$ d2 v: t SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);* \0 r/ i% ~4 D" _* Z+ [ Ret=Ret&&DeleteFile(Tmp.c_str());4 {0 |# C" m" ~/ a5 c* T) f% k4 i' p }1 T4 c' i- J! v7 V8 W8 @5 T } 1 O' Q$ V2 O- f; Y' f" U, V bFind=FindNextFile(hFind,&wfd);8 ~5 _( h# r9 W } w1 ?) b9 M2 c: R9 s! X- Q8 [ FindClose(hFind);/ f& i2 c1 [% I }1 w6 J$ k3 D4 ?0 M& E& [, e if(Ret)return RemoveDirectory(Path);2 A, @4 F# C* K/ x return false; , i) g: H! z% a* a; q# f1 |" ~2 v} , f; ?" z' I0 p; X$ T: F5 N* v% ^

* Z4 p4 |8 [8 h! A

% Z+ \% k2 R6 Y) {. y9 `1 |5 N

zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2026-4-20 11:34 , Processed in 0.296051 second(s), 51 queries .

回顶部