QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

- I# R8 a$ O* o- c6 R3 ~( o- I

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

# W$ \0 r( g+ _) ]& x" m# c

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

" O, j1 T( e# k L

一、判断目录是否存在:

% \! o/ S6 c2 w2 q9 Q3 q6 ?

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

; b: D g/ C: F' K- R7 f

设char *Dir为带判断的目录4 F: r/ `3 H4 Q4 s3 Q bool Exist; // 最后结果,表示目录是否存在 0 X( O! Y7 c8 ~2 gif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” 7 {8 g$ i: P3 G7 ^. @, sWIN32_FIND_DATA wfd; // 查找/ s6 U% r( N8 r% _0 n# L7 I8 R HANDLE hFind=FindFirstFile(Dir,&wfd); 4 O3 w5 T" } Z2 H; j7 ^4 L if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 7 g. [' R* W* n9 qelse . u K! u9 \ P4 X5 g' [) j" R{ T3 V- o N+ \# K if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录* Z- k) ~) \! M& d Exist=true; // 是目录,目录存在 - X* k, q8 X; K; k3 b9 T else$ ]4 a) l2 f$ w! C. v* Q" B" @ Exist=false; // 是目录,目录不存在 0 s, k0 K2 S- p FindClose(hFind); , f" r/ |, j5 V6 t. ^ L8 O1 ^}

1 Z7 d+ K- E# F0 n1 @- _* A

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

* X7 \3 k8 N1 w2 s

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

& a. Q' T4 G4 ^6 O/ |3 y ^1 O

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle # y3 A. o, _- E5 N" NLPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL 9 _ m& c8 h4 `4 m, k1 gLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 : e+ z$ w* M4 M: ?LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 4 ?' M6 [* G( c, @, H6 |8 S1 { UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 1 T% w( M' t* A3 x3 DBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL . {- v; W* F) _1 eLPARAM lParam; // 预定义的对话框传递给回调函数的值 2 o9 n) G) ~9 y" s% d Cint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 - r) ^) J! J0 q- m9 ?可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: / P, q. C- v; S. z% y #include <shlobj.h> // 必须包含的头文件 # u' \1 n1 b4 J8 [2 Uchar SelectedDir[MAX_PATH]; // 最终结果 : `2 A& n& W- L3 y6 K* fBROWSEINFO bi; // 入参 - T( C5 s( f* r0 a) N5 r- `" ?" Jchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font W" i J9 z9 W LPITEMIDLIST ItemID; // 所选目录的系统标志指针

0 s0 L- t+ {# B4 s* F$ k1 b- _8 m

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 ; [5 v# p. J) g- ?1 Wmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 + C4 \8 Q# f& a- {$ O* `8 V* Wbi.hwndOwner = Application->Handle;) b# f! }( v/ Z1 S6 { bi.pszDisplayName = FolderName;/ v. G- d% U" s/ k% E$ h bi.lpszTitle = "请选择目录"; // 改成自己希望的 6 v; @7 G7 U/ B4 Z- Jbi.ulFlags=BIF_RETURNONLYFSDIRS; ; W/ X2 [6 I7 I" O7 `ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框, G+ R/ Y. w+ p; g9 W2 b9 m if(ItemID)4 Z, R Z* e( u$ W( z9 F { 6 v4 F0 H7 I6 _; m+ i SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名; T! q e! A- J; `6 u! g. V1 X GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 ; ?/ d& ~0 y ^}

- X4 z/ |1 R) i# T: k' s

三、直接建立多级目录:

9 P) y, L/ f# |) m! b2 `

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

9 S$ H* N: o4 S

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"2 n! h9 k; D/ @3 u2 U2 U { 6 Y/ X3 J$ l+ U W i2 r/ u. o5 C if(P.IsEmpty())return false;4 ]3 _# O! i+ o: s9 Q$ P. a int len=P.Length(); / P$ G- l6 x/ T$ R; F N char *Path=P.c_str();+ o+ z) L8 f/ ?8 I J0 w if(Path[len-1]=='\\')2 N/ `+ A; ]/ ^- M* @4 u { ' `/ b6 A9 q1 k; F len--;8 m& c+ y( t( b% l Path[len]='\0'; 6 V) Y" w" k# @4 d1 p/ s } // 删除末尾的"\" . t" R. n v1 ^4 z9 j7 V, e6 i AnsiString Dir=Path; 7 ]4 s! [- ~( c8 G // 分开父目录和本身目录名称% @% }9 z+ e8 m+ o! H AnsiString Parent; / C) T9 p7 [; z6 i) o for(int i=len-1;i>0;i--)9 G( U" s1 R: i4 p+ ?9 u { # R2 H1 \- A" `. ]# j0 ^ if(Dir.IsPathDelimiter(i))7 @& S" }" I5 z' R7 y {! ]+ a2 Z* ]& _. m, f8 ]) U4 ` Parent=Dir.SubString(0,i);+ J' ^6 S+ I# k8 P$ F break; $ @; J Y \8 V1 k% i, I }" a! X, l8 S$ H: t+ o( B) }/ ~ } - t4 j/ T' Q* j2 Z, R if(Parent.IsEmpty())return false; // 目录名称错误 8 q0 P7 |4 L$ J bool Ret=true; 7 z% h) T8 ~; k' t if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 3 }8 O& s' P8 @; V$ ~ Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在$ y' h; b+ M) n9 i0 Y" L" k if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 * U/ b, g/ K% z if(Ret) // 父目录存在,直接创建目录1 ?, @: u; n$ L4 w { ( E( r2 J$ a5 _+ W( g SECURITY_ATTRIBUTES sa; : }* k" S* D; k7 M& k6 Z/ \# y sa.nLength=sizeof(SECURITY_ATTRIBUTES);; I& q k) i# X- R' A# v) h sa.lpSecurityDescriptor=NULL;, e1 L! I# J% u0 S' | sa.bInheritHandle=0;# G% j; {8 n$ u0 O6 b5 j Ret=CreateDirectory(Path,&sa);8 L9 L" R; R% G }( c" C! M- k; X! l return Ret;- @( b# V, ~+ J1 } ^ } ( K9 i$ m, D6 @4 w 可以看出基本方法是:$ a5 U8 F7 O. L 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; 3 a; ?- N2 L5 Y/ G% k 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

3 v) R1 F; d$ U+ k( s3 q

2 p: v( |: s% A6 N+ J8 k四、直接删除整个目录:

( a+ ^7 @7 a3 s0 L7 @7 P/ I: B* p

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

" a6 E& J, |" ^/ ?; d

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) ; e" D: O5 p6 J: M! R% W 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 7 Y8 e Q: Y9 v B 如果找到目录,则进行自我调用,即开始递归过程。 & U" @9 q& O5 I8 B' B6 O) ^ 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 + G3 G! |/ V, n具体程序代码如下:

4 m: C8 P9 F5 ~6 ?6 S& o3 F$ c

bool DeleteDirectoryEx(const AnsiString &) / X7 w7 h3 G2 F Y+ K" K. H. y{ : M+ x: r9 q. A) n* K& a. [ if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 6 o. {4 k4 C% V* X, y, l int len=P.Length();$ M) k1 L' ? \6 ?6 | char *Path=P.c_str();4 v/ a0 N/ D/ E/ Y% `# H2 c AnsiString Dir=Path; ! }, e. k) B! O$ Y& Y% l if(Path[len-1]!='\\')Dir=Dir+'\\';- z2 J) d/ c, q2 n- [3 i AnsiString Files=Dir+"*.*";8 ]( I+ Y; m) A1 q j WIN32_FIND_DATA wfd;) B1 L8 I0 J% o HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); ' ?5 k e. @7 S4 a bool Ret=true; 5 \/ Y( V2 Z5 n, A( q+ T+ s7 { AnsiString Tmp;& X0 ], y; Z5 ?( D if(hFind!=INVALID_HANDLE_VALUE)1 Q" Y4 C' w4 |0 n" w {( E) k/ m0 ^! j6 A/ Q0 _1 K' } bool bFind=true; - C4 K- f( O/ ]& `3 N- o while(bFind) 2 w6 |( u6 }' X& m4 @ { 1 _, X+ t B! w if(wfd.cFileName[0]!='.') // . .. 2 E4 L# V ?0 R; X9 t { $ b3 H7 @& c4 u8 @ Tmp=Dir+wfd.cFileName; 9 e+ n) b6 I6 U0 o0 N5 B if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ( b9 d/ T& {+ {: Q( A { // 删除所有子目录 ) ^8 w/ s! x$ Z6 {" U ~+ Y Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);/ F$ Q; O( z- @: B5 P4 s' h8 y }else / }9 n: V/ b1 ~$ R { // 删除所有文件 4 z4 b: o9 p7 t5 @0 \* c SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); ' E* q. h2 k( I/ H+ b: p Ret=Ret&&DeleteFile(Tmp.c_str()); \+ E! a0 x+ i# x, l }9 D3 {0 |$ T6 A, b }/ G# z( ]+ I+ N H4 s bFind=FindNextFile(hFind,&wfd); $ p6 v: D) A) d/ W+ B7 H. k }& Z; S* g! U7 R0 \2 _ FindClose(hFind);" {- Q% M, y3 h0 u5 v3 m3 c } % c* Z0 z+ W8 T( X, i if(Ret)return RemoveDirectory(Path); % r# b) n! Q: ]5 h" b return false;5 R3 D$ e3 `4 R3 H: K# w } ) }' T$ ~) p2 P# p+ a+ S

9 a9 I% H* `, X; ]% F. D3 R4 ]& c* B

, g# y/ R) `# s* i2 N6 c

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-8-17 14:35 , Processed in 0.598965 second(s), 52 queries .

回顶部