QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

5 ?* E& g! D: c6 [. a: p2 e8 X

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

8 b" ^ i1 G% }4 ~ m, E* }

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

) P4 `$ p T( X: _4 C

一、判断目录是否存在:

2 F: v5 Q2 K6 X# z! x

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

0 x! a& ^9 u, N1 q$ M" t

设char *Dir为带判断的目录, \& Y2 n+ E' D6 X" h bool Exist; // 最后结果,表示目录是否存在 . X% F1 }+ U% J% ?2 L; Iif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”+ V+ u/ y* E( W$ p1 w WIN32_FIND_DATA wfd; // 查找% y# P9 r& p* y( P% G: i* Y | HANDLE hFind=FindFirstFile(Dir,&wfd); 7 ~: P1 P% e- D% O if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 2 r5 B8 _! J3 w6 i1 Ielse& p8 @0 w8 X. v7 A) u5 g; \: | { - p+ [' W! G5 b# ?! h9 W if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录& h( w; \: @4 T! T6 G% f Exist=true; // 是目录,目录存在 7 X8 p# F+ c. _/ ^/ ~ else 8 z5 K b* \* E5 i Exist=false; // 是目录,目录不存在 % { a% B) Y ^ FindClose(hFind); , G: } d/ L4 N; d5 @3 H. }}

3 a0 m- F4 N/ B# q) r7 I! ^$ ]4 i- p

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

- w, A$ u) a* W& n/ f0 }

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

9 S, l- x" q% l

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle , H- E1 j: ~4 q/ N LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL* `+ U m: T" i- e LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 / y6 j' A; b! ]/ Z5 h6 h/ n LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 4 C! n5 y$ A1 j4 m) \. pUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 7 w% L; N2 a8 XBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL ! p c! } s- H8 r3 `LPARAM lParam; // 预定义的对话框传递给回调函数的值 ! m3 w" y, N" f. i. jint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 : y% c; u, n- _3 r' Z3 k% N) }$ c2 ?可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: % Q# E7 \& ~8 ^% B, x8 z$ \' t#include <shlobj.h> // 必须包含的头文件 6 b7 u N. W2 `/ n7 ^9 Tchar SelectedDir[MAX_PATH]; // 最终结果 . r# D+ F1 F7 V7 g4 P' `BROWSEINFO bi; // 入参7 Y. ]/ o& z6 F- p) P char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font - x, l8 |: I5 V LPITEMIDLIST ItemID; // 所选目录的系统标志指针

9 M$ e6 f* d# d5 ~& t# w

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果0 c& a9 B7 c1 e) S) o7 F memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据$ g# f3 h, N* X S4 p0 y8 c, j- x bi.hwndOwner = Application->Handle; % `3 E3 j4 b0 P9 _) E \bi.pszDisplayName = FolderName;( q7 |1 L* l. w# x2 Q bi.lpszTitle = "请选择目录"; // 改成自己希望的 + g2 a. w" W [bi.ulFlags=BIF_RETURNONLYFSDIRS; 8 H' g3 a! T, B2 n2 B" CItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 ! C# l: s% F! Q$ Sif(ItemID) M3 ^# o% N' d8 E: h7 D; ^6 {4 p# N {" O* e1 N8 b8 f$ u SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 & m! h& q0 s+ H& G$ P0 ~ GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放* X$ s9 d+ C" @: a3 y }

. s# l6 \: U% Y& W" n: e8 N

三、直接建立多级目录:

) A& [3 T* Y9 G+ Y. v

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

4 ~* e5 ~; T0 m; o5 w0 U: y

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false") q: f) g) {4 E" U {. y0 h1 D; V$ S5 P if(P.IsEmpty())return false;9 `+ Y- x4 s p+ h& V& {* E8 J int len=P.Length(); % {6 B# h4 K; a7 A8 Q/ F char *Path=P.c_str();4 x* b' c# i5 b. U4 ~ if(Path[len-1]=='\\') 4 o( u6 x6 A. T$ ?3 s3 q { 1 R3 T; \' g# h len--;& L% |; I0 A3 @# Q2 X/ B Path[len]='\0'; * J( d5 y: N6 K o, |! G! K } // 删除末尾的"\" . @$ i! z7 Q2 m! ?! d AnsiString Dir=Path;, Q: o8 `. B5 }! ^ i // 分开父目录和本身目录名称) ~8 s. P2 M' x3 V% V: ?0 t, }+ z AnsiString Parent; l1 P+ N0 Q/ ^0 M1 ]/ I0 e) K for(int i=len-1;i>0;i--) 3 j/ d% B7 h+ g {9 n$ ~! P2 ?8 J9 g if(Dir.IsPathDelimiter(i)) 7 S- Z) u0 h3 s3 ^ { % u& t. \' y7 x: Y. N Parent=Dir.SubString(0,i);! M! }1 w( f" B1 x X( n s break; B- A ?% g( ~; a; \ }: m" e! ~" W# ]: P }( F9 S$ |' {0 R7 A7 t if(Parent.IsEmpty())return false; // 目录名称错误9 a/ b$ o! m6 [( S bool Ret=true;- g" {5 P( f. A! O% n! z! p6 b0 t7 I if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录" j0 x" ?& }" q0 d6 x" p: @ Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在; Z. a; l5 G. J% V if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录5 X5 `6 D1 [" c7 _ if(Ret) // 父目录存在,直接创建目录 ( p2 ~" R- }/ r' x. Q! ~9 \' w { 0 a6 u+ }* w3 F+ H' Y SECURITY_ATTRIBUTES sa;9 J1 [9 Y1 H; m sa.nLength=sizeof(SECURITY_ATTRIBUTES);; {& H. Y$ q' N5 J6 m sa.lpSecurityDescriptor=NULL;. w" J1 g2 r% a# d- D9 W$ ^6 _ sa.bInheritHandle=0; + Z8 E: c% m: r( y Ret=CreateDirectory(Path,&sa); ; ~' X7 \# d4 J } & D% z6 X' A) k4 A return Ret;: i, B2 F4 D! Y! j- Y } 7 P3 {6 c8 w/ j 可以看出基本方法是: 7 p& i. O/ B5 L7 V; t先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; * K4 j( \. L; B t! ] h如果父目录存在,则直接创建目录,否则自我调用创建父目录。

5 j) s5 t- }& f0 Q6 S% `

$ b- S' @' T. A3 D四、直接删除整个目录:

/ f Z" {9 a; c) n+ u1 A. h7 _9 S+ D

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

7 r) T8 ?3 o+ P* L

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) l: f1 G( R3 @, m如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 3 s4 x7 f4 N% P如果找到目录,则进行自我调用,即开始递归过程。 2 O# l3 K+ {8 W# X. \7 p 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 ) h8 Q. l- W( i4 }' O# f 具体程序代码如下:

$ Z7 I8 E5 D% i

bool DeleteDirectoryEx(const AnsiString &) 7 x9 M7 X* d# ^7 y{/ i1 v7 G4 T+ p4 ]5 i2 F if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白9 I+ O4 ^ k; _) z% V6 Y! i int len=P.Length(); 2 ^- {; N* n( K0 j; x% _; _ char *Path=P.c_str(); $ v- U) l: _0 j; h' ` AnsiString Dir=Path; 9 F5 w2 F, p1 X2 Q1 A. A if(Path[len-1]!='\\')Dir=Dir+'\\';9 C2 n; D5 f( u/ r2 } AnsiString Files=Dir+"*.*"; 4 `/ k$ F9 c/ c! U8 [: X: v WIN32_FIND_DATA wfd;' s- q0 D3 r( {, H) d/ Q; W HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); . ~7 h0 a$ t. @ bool Ret=true; 0 k6 E2 r% R. ?2 f! S+ M AnsiString Tmp;1 S- D, q( |# I& i1 H if(hFind!=INVALID_HANDLE_VALUE) ; h! L- }0 s" p5 Y8 B { 5 z4 y6 o, i$ K/ v1 @: O4 L bool bFind=true;0 p- R) q* g8 h \" t! w* ~, ` while(bFind) , i% ?, G( s( u4 w$ }3 B {- x' R. e% @) u/ [ if(wfd.cFileName[0]!='.') // . ..% x! N! r" ?- r, d0 D6 T { 5 F) l- ^/ ]) c9 ~5 {7 M- m Tmp=Dir+wfd.cFileName; $ f) M4 y# h% `; a if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)! a% k+ l, c5 c( a { // 删除所有子目录# x- t; o+ e8 O, E+ }1 S7 A1 N Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); 1 s# F) B, W! X3 n$ j }else 0 l( u+ x( T/ Z3 V' p { // 删除所有文件 1 J# X( j: x/ d' O- S: a3 U$ O, y SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);0 U. T, k3 W) ?: m Ret=Ret&&DeleteFile(Tmp.c_str());$ |% M+ m E, A8 U8 \& a } : ~' z& h3 U7 X; ?1 I0 S* m } * R. B p& y# P e9 [ bFind=FindNextFile(hFind,&wfd); ( W# ^: _) V' K/ A0 O } / h( W3 p# }+ i6 ? FindClose(hFind);1 t' d+ H$ C# o% W; K1 a0 c }; m) w6 r9 ~+ U7 L( P2 F if(Ret)return RemoveDirectory(Path);" I3 N5 L1 {- K7 B' U return false;- C+ H/ ^1 ?0 x* t/ S+ D, r } 2 D4 W* Q1 n- m1 ]' t1 A: p# H

' X2 @( a9 |! p9 N

p9 N/ s- o; \% J. u P! d) k

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-6-11 10:26 , Processed in 0.380871 second(s), 52 queries .

回顶部