QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

F' G# _( W- o- R6 ]# c+ _

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

" ^7 \7 d" P. W/ @

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

! j$ `" C$ [( [+ ^0 y5 a6 g

一、判断目录是否存在:

/ k1 e; a2 Z8 t/ [0 _: i

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

5 z% D9 u2 `/ P) G Y

设char *Dir为带判断的目录 " s0 Z0 f' P' M4 `0 S; ybool Exist; // 最后结果,表示目录是否存在 h) a: K2 j1 N% @) Z/ ]8 S N if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” ' l! y4 g% R8 z0 Y; s7 W# dWIN32_FIND_DATA wfd; // 查找0 c+ ^8 q2 _4 g5 E0 c% Q$ b; x HANDLE hFind=FindFirstFile(Dir,&wfd); o) q( w6 m/ H% A5 X& S if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 5 h* O$ [* o8 \( Delse , T, l4 i; C. s( j7 P8 {{' C6 [$ K4 x9 s4 ^ if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录: M4 z1 ]! r* w" s& z: J0 e9 ]% U Exist=true; // 是目录,目录存在 + s) A+ ~" C; ^0 n4 y7 A# J else6 [9 {- v! u# Y/ |" h: n Exist=false; // 是目录,目录不存在 7 S6 i! e. X- z9 U; g FindClose(hFind); 2 L% l% T# f1 j3 d- q _: j}

0 J! b8 W" J2 }* [( \6 ~. W* G

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

: l0 h4 l2 k! Z' d$ N% c

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

$ b# N8 B( p4 O

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle $ Z: s3 A+ p, A- G4 J LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL/ u0 ?: x) [+ q$ B6 ?" C2 r LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 7 g: f2 @& ?: U, Z+ FLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 # n2 C6 P u. e6 i. TUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 2 `6 }5 L& V0 J: MBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 5 S1 l5 K8 F3 Z& z LPARAM lParam; // 预定义的对话框传递给回调函数的值8 U9 k+ {/ B7 d/ b) O int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 $ o- y3 U Z/ F 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: : N" G* Q1 N7 `#include <shlobj.h> // 必须包含的头文件$ K$ z7 }2 {, ^; ?# J char SelectedDir[MAX_PATH]; // 最终结果 6 b* p( a8 Y# K; l6 mBROWSEINFO bi; // 入参 , h. f1 z* d9 \5 N4 H6 O% |( {char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font : c( ], D. ~( Y" J* j9 w LPITEMIDLIST ItemID; // 所选目录的系统标志指针

0 y% B$ [/ O" V7 m

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 6 q7 T% a" s) Y5 L0 N) Q3 G% j) fmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据. k( u3 l* K, R O/ w* m7 A- }' j bi.hwndOwner = Application->Handle;6 Y4 {& M, }4 d9 M bi.pszDisplayName = FolderName; ; z: X( O: r- t& cbi.lpszTitle = "请选择目录"; // 改成自己希望的 , f* V+ F% \( W0 {: W' b3 _bi.ulFlags=BIF_RETURNONLYFSDIRS;6 c# x7 e! {$ c ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 0 Z, V( ^0 F; zif(ItemID) ) T( S6 E+ K0 b{' A4 ]7 E7 K4 l: ]/ }8 r SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名) i5 L# a4 U+ f GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放7 Z- G* p; r1 M$ r* H$ Y& e0 t }

% k& ` C! M/ i9 l- i- ?, a4 \

三、直接建立多级目录:

7 v& C1 X, X. R) T2 u

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

/ t% r$ C6 D5 l% ?% P

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"; T; {0 d& K% k5 G {+ D3 _% o9 z+ @9 X7 { if(P.IsEmpty())return false; & m9 ]" V, h* A& u% P0 \+ C int len=P.Length();3 }; f4 f6 O& v& b4 W char *Path=P.c_str();* O+ D. G o! i if(Path[len-1]=='\\')8 ~2 T! |8 e7 o/ [3 |2 ? { 6 z, d0 x. \" d len--; 7 ] R- [9 Q: g$ C Path[len]='\0';8 T9 X+ \9 R2 [9 G } // 删除末尾的"\" # Y. ?4 E6 M1 q AnsiString Dir=Path;2 z3 ~/ h E6 T/ c0 E' B X' R // 分开父目录和本身目录名称 j& A0 u' h# n7 I AnsiString Parent;, V7 t- ~6 K1 c7 U" J for(int i=len-1;i>0;i--)' n+ `/ v r! l( A# B {* s4 Z+ J% a" u$ I2 |5 u if(Dir.IsPathDelimiter(i))' h: G6 ~ N H; f% u2 O {3 C# q; t7 H: U& i6 ]3 p. N L, s Parent=Dir.SubString(0,i);( D( @. ?* j$ f break; 0 F% ` r% _% l; |( E4 O }* E" G& K y: n1 A. O" M }) R% K! C) Z c0 F0 L# J/ l if(Parent.IsEmpty())return false; // 目录名称错误. Q( h, B, _+ [* e5 j* x1 t, c# t bool Ret=true;' G, M7 X" W+ a9 R6 H% k9 ]. N2 Z/ k if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 7 X; h+ f7 O% }# P Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 1 {0 P, O& R* H" q if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录0 Q& O7 j6 H: i" X4 U( j6 c0 O( U if(Ret) // 父目录存在,直接创建目录 1 [9 h7 X% r( f: p7 F5 l4 Q8 _ { t5 c& |. V- \ SECURITY_ATTRIBUTES sa;( D6 q* ]" J' k. J6 T/ [' U7 f sa.nLength=sizeof(SECURITY_ATTRIBUTES);3 t# H. M$ D. x/ U sa.lpSecurityDescriptor=NULL; " T- b% Z: Y/ t# q5 T: s' B% j sa.bInheritHandle=0; . j- {& i# [9 O9 b$ z% q Ret=CreateDirectory(Path,&sa); A; F$ x6 {5 f# F } & }4 l8 o( n+ [& Z$ g- V return Ret;; Z9 C0 e8 P) `& y4 A5 f } 7 B' I5 U! O% ?9 D+ o 可以看出基本方法是:& F% ]# [: ^5 `0 Z7 n7 p1 W7 w% Z 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; & r* k* h) M2 M如果父目录存在,则直接创建目录,否则自我调用创建父目录。

* I. b4 \8 v1 r* g

1 ]# x& w0 B0 ] u/ x 四、直接删除整个目录:

; B0 F6 ?5 h9 T

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

! M$ t8 c6 s x; _9 A& j

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 2 q6 y5 @6 m1 k F9 `! d) U4 n( d1 i8 X 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 4 X. L5 d O. v& C 如果找到目录,则进行自我调用,即开始递归过程。 7 c% y- a6 D3 R* B' T* u) j 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 4 x* d E8 p3 U9 {/ i具体程序代码如下:

6 X. g% z) w; ~ G

bool DeleteDirectoryEx(const AnsiString &) 9 g u5 D8 N' C; V I{' A& ]5 V3 h. e- V7 {& G- {( i if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白8 `1 f% [3 v2 v1 _2 p int len=P.Length();8 h" T2 x- W0 b char *Path=P.c_str(); ) N, p1 G' k! A) ^1 l, x AnsiString Dir=Path; 3 f$ \- x$ R) } if(Path[len-1]!='\\')Dir=Dir+'\\'; % z8 L5 e( r8 _1 a J( ` AnsiString Files=Dir+"*.*"; ) j, h( g8 b' r4 q% d WIN32_FIND_DATA wfd; # m7 s! t2 O& `' T" d: z HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);% _" ]" G& S0 q' ]4 f8 B bool Ret=true; O: }" ?6 i' E( ^* o' e- _ AnsiString Tmp; 0 E( v1 G! ]" c1 l' a, Q if(hFind!=INVALID_HANDLE_VALUE) : H8 q# |& B' S/ c4 G1 J+ T {# M: b$ |2 d5 L$ u( {" v bool bFind=true; 0 {: b* `; O, x* q6 S while(bFind)- O) I. B& j* v7 R o. ] {: H8 w; e8 c3 b; O$ j; I if(wfd.cFileName[0]!='.') // . .. ; E; Y# W6 L6 E { - G0 A/ K h- f; {8 I Tmp=Dir+wfd.cFileName;! p# G2 r/ l/ T if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)% S; }( E5 W: H; O { // 删除所有子目录* |% Z0 R& a$ i% W1 |: w8 J Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);! z+ `- h; f% q6 [8 w }else$ \3 m+ M/ A) d# I { // 删除所有文件 * a# L8 t. C) m) t% Z9 N8 {6 { SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); . N9 s% J! [1 ? Ret=Ret&&DeleteFile(Tmp.c_str()); 5 A" _7 G! I# k0 B. e) V }( ^2 i2 |2 I; V" X F9 | }) E: M4 g5 ~7 B- V5 o bFind=FindNextFile(hFind,&wfd);- s4 |1 Q E" g( h2 |: G }; q8 r* w6 D+ o" _ \ FindClose(hFind); : j/ l5 a% G) h } , K! t( I3 C- G% q' J3 D. j if(Ret)return RemoveDirectory(Path);& v# F7 f6 p3 a, N* { return false; 2 P4 E8 E' p1 ?} B/ B' R6 S* W( _3 s

( U: e/ w) a% U2 b2 p5 {' T

$ I9 K; s* j1 h% G: Z1 O' ~) P4 J

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-5-5 19:44 , Processed in 0.428903 second(s), 52 queries .

回顶部