QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

) C( d: n0 ~$ X$ g4 D4 k1 z. ]

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

3 z/ e+ q; U9 E; z: v, V5 y

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

4 R A! e- G4 k+ p: b( b6 b2 p

一、判断目录是否存在:

$ l& j0 {) J! u* `: E; L

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

" ]# \9 T7 A8 X6 ~# y3 G5 g( G

设char *Dir为带判断的目录& q* q* g0 _( G) h, _+ H0 h bool Exist; // 最后结果,表示目录是否存在7 u: X i, T5 \& d4 o if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”7 }# K+ k! Y5 \6 }) a WIN32_FIND_DATA wfd; // 查找 0 L8 ?& g f1 n$ U! h9 k: F; KHANDLE hFind=FindFirstFile(Dir,&wfd); % K: J6 l& o+ z if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在9 M9 O" ^+ j/ `: Y6 k* b/ P" G2 Z else 8 _+ K& f" A8 _/ J- y. B! ?{4 V2 u: C$ a6 h: p$ B if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录0 u1 F% y, s* m: a4 ]# L! p0 F( | Exist=true; // 是目录,目录存在 0 O4 O7 x0 I; \, I; H( D# B0 o& | else 9 C; h/ c) O6 J4 }" F! `( U Exist=false; // 是目录,目录不存在' N- o( e6 a* M8 i+ M3 n" T FindClose(hFind);; {1 B8 ~3 O% D }

0 x2 |2 t# r* j4 ^* Z

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

# |: f. i1 `0 k. }% S; E6 I

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

6 S; O4 p: \2 {2 E. U

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle " Z/ d# W& c3 a( O3 O* Q) q LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL2 B) t0 p/ i" B) M. F7 y9 ~ LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 ) a7 g. H# G# q7 NLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 4 i" u9 ?, e/ D# \0 pUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 3 @1 K2 E! f; T6 T. UBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL * L8 Q# h# N# W( fLPARAM lParam; // 预定义的对话框传递给回调函数的值 ; M; C$ n: H( D# Z5 cint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 - r d- v4 i" R: z可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: ( I0 a; U7 B0 I. o, V! n5 M#include <shlobj.h> // 必须包含的头文件/ ?6 l/ o* _ f# Y( f char SelectedDir[MAX_PATH]; // 最终结果! D a8 O6 W4 m6 _ BROWSEINFO bi; // 入参 T S3 I) F) h M( \ char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font & x/ ~6 i: H9 R: ^ LPITEMIDLIST ItemID; // 所选目录的系统标志指针

( {, _, j* O4 z1 W5 ?, c3 t3 V# ^

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 ( z# p3 K$ G' {) }, Smemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 + j: X6 C2 o8 G, j% Q3 Obi.hwndOwner = Application->Handle;& ^ {7 O5 A0 `5 {2 m9 L bi.pszDisplayName = FolderName;! f- l% }2 H1 o8 d6 k bi.lpszTitle = "请选择目录"; // 改成自己希望的) S( y- i6 m5 b3 [ W- E bi.ulFlags=BIF_RETURNONLYFSDIRS;, F B5 _ B" H0 V/ w ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框' o/ B+ j8 r6 ~: C0 y if(ItemID) + e7 O: `: ^5 e: ~) \( E. j& P{ % h8 D' O" {1 R, r6 w5 [ SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名* i5 n/ m6 V6 G% l+ g GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 8 U* ?& f8 v. j7 X2 }2 t- z& q8 E! I- Q}

/ x% ~9 d" ^* M" A

三、直接建立多级目录:

7 L6 b& b7 E7 V4 P8 w2 w# _

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

$ k7 j( x8 u2 L& U

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"; d3 r2 x+ R* _6 }9 V { , O3 j4 [& C A$ l if(P.IsEmpty())return false; 9 K6 r" K: J: t2 A; { W/ ^ int len=P.Length(); 7 p: S: y! \% C, f char *Path=P.c_str(); 8 I) V" M8 ~0 N3 Z! O1 g if(Path[len-1]=='\\')2 ~6 `5 D- e" h% M { ! l5 m, f. O I6 D' B len--; 1 Y( @2 ` U" d: |! o Path[len]='\0';8 U7 U; J# V+ f c! C- d } // 删除末尾的"\" @0 X A/ @& k W- P0 b- ~5 ~ AnsiString Dir=Path;0 ^/ A' q- N# H2 Z: \ // 分开父目录和本身目录名称! Z; g) N5 T, Z* @ AnsiString Parent;4 `, ]2 R, @+ [ for(int i=len-1;i>0;i--) ! f% l9 |9 Y6 l! j( A$ R. G {1 ]# {9 v1 s7 l/ M' M if(Dir.IsPathDelimiter(i)) - r7 E R& D( h3 f) X { / g8 J }5 s) b* v- l' \ Parent=Dir.SubString(0,i); . z, q/ r% b5 K) B' a. Q2 c4 p- {" G* ] break;- p5 e% h6 ?5 N4 c$ V }. n4 u" Q* Z. z5 k } 7 ~ }0 _5 q- W' x: B, ^" ~' I if(Parent.IsEmpty())return false; // 目录名称错误7 ~' B/ W3 C+ U1 u/ S. Y bool Ret=true; # ~% T, `3 p. C. ~+ { if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录! @2 B$ m# c$ H! C% Q Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在; |, n4 C$ m$ P0 [- s( h E if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录5 n3 i! f+ N, G+ c+ P' z/ M9 C% i3 y if(Ret) // 父目录存在,直接创建目录9 j, O* P- k6 q! s' u h { 1 F: X8 j# w8 c) I( R7 j2 h+ b+ R SECURITY_ATTRIBUTES sa;. x8 T- Q) |) T/ C sa.nLength=sizeof(SECURITY_ATTRIBUTES);# e. ]+ U+ o7 ?+ [- c+ F sa.lpSecurityDescriptor=NULL;3 S- R& p3 x; Q& G/ T* O( Q( s. i sa.bInheritHandle=0; 5 B/ t7 N" T9 n0 g( O2 o Ret=CreateDirectory(Path,&sa); J' f+ z! y# Y) K }; z# L6 Q$ \9 E1 [6 } return Ret; 3 l- y' r. z! P2 X: r} ' T" h0 _1 G; h* P 可以看出基本方法是: $ K: X# L1 W; h. W先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; h) Y. b( W+ X' t$ r# m( g0 z3 Y如果父目录存在,则直接创建目录,否则自我调用创建父目录。

+ w) G* ]; L" v! h, c1 ~; U

z! w1 J" _2 e% `9 z四、直接删除整个目录:

! e& u" D _, I: ]

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

2 C3 U8 R8 X7 j6 z. D) g; q2 f4 n

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) * v+ p& c1 Y- s! _$ q2 S0 G 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 ; G7 R+ }. a+ U 如果找到目录,则进行自我调用,即开始递归过程。 7 J; D4 y! l% Q; I0 W0 V! q 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 , ~( w; Y' F; C' S具体程序代码如下:

' q% ~$ T$ c( L. U% r& x

bool DeleteDirectoryEx(const AnsiString &)3 q. T- N- C6 }" A) ^ { 6 m0 V* E9 b- ^1 f+ V if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 ; x$ a+ Z( n! d+ ^2 Q. [* s1 m int len=P.Length();% ?4 |4 a8 P. L& p char *Path=P.c_str();8 T4 n' l( J- K3 s- b AnsiString Dir=Path; % i A$ D3 R9 x( u8 O+ L3 r" C& V if(Path[len-1]!='\\')Dir=Dir+'\\'; - f9 r8 ^* J% i! i; R AnsiString Files=Dir+"*.*"; ; \6 T& o5 E4 v$ \$ x WIN32_FIND_DATA wfd; * @, [3 n, f5 @! h HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);. q9 _- ] N# A! M8 E4 r bool Ret=true; + k4 O# D7 V$ n& k V; y | AnsiString Tmp; 9 @* y- F' i8 L7 c if(hFind!=INVALID_HANDLE_VALUE)5 U7 F# G1 l; x/ ~! i4 w: W8 _( v {( e8 U" d& R1 {' a# I5 H bool bFind=true;; n) H+ w1 ~$ N& Q3 W% a while(bFind) ) M; p/ e2 @- A, p { ( D* V5 P6 O4 o6 ]! n, u* m if(wfd.cFileName[0]!='.') // . .. / B! i/ m8 X; V/ s4 r" w {8 ]" M: k+ `5 [ Tmp=Dir+wfd.cFileName; * t+ k- e% e! z1 g if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) % l5 O% Z' G/ T8 g* b { // 删除所有子目录 % }- v2 Z) g: X: @ Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); " v& C6 P! d/ B2 } }else* U3 l$ J4 I& |& i! [0 {; Q+ ^ { // 删除所有文件5 N# P6 D6 v! ?& }8 w" N. p J SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); 2 C" |& B i: T7 j7 c+ N. r+ w Ret=Ret&&DeleteFile(Tmp.c_str());# c7 m( ?7 ~% g" A/ U } , c. ~% a# _+ z } ! A' }. g3 T( u! F( o! {5 g bFind=FindNextFile(hFind,&wfd);+ L: H- D# D' ^+ D3 V8 m0 y } ) y8 i! @8 \1 O5 q" s/ b5 y5 w' x- D1 p FindClose(hFind); . s: e. Z2 i, M8 b q }3 K1 b! |' _$ j1 @ E B4 m if(Ret)return RemoveDirectory(Path); 6 ?! d. V: K8 E7 q* C E9 ^ return false; , V* g& F, m, `4 g0 d) i2 y} 7 w; U/ o4 ` @. i1 p

# f$ o- e) Z2 L" V3 f6 F* R( n

) v2 l. C0 M+ {5 x

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, 2025-8-18 16:13 , Processed in 0.378709 second(s), 51 queries .

回顶部