QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

/ _9 V% T: D$ E0 R2 g6 g

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

' B# A! _; p) J0 k4 \. |

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

2 [+ V1 z" G7 ^: W6 W, X' R! x

一、判断目录是否存在:

/ m& t: n6 ~; _+ k- j8 W0 {6 B

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

; E0 t+ h4 P2 D. O3 I0 o

设char *Dir为带判断的目录 ) f$ d0 ?( J+ q6 x- Abool Exist; // 最后结果,表示目录是否存在* {" e, x q4 T: x if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”! I1 P5 f; C$ Q WIN32_FIND_DATA wfd; // 查找/ I" R: c' ~: O/ E HANDLE hFind=FindFirstFile(Dir,&wfd); 6 M+ i) I! i$ i( u8 h, o if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在6 u2 t; g2 U% x else 0 U" G, }% e3 G. I! r{ - F' j5 {2 w5 `' Q) k if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录; a; m* h- o0 ]: A* w8 L Exist=true; // 是目录,目录存在 4 o" O0 I* [ {0 x" l( _7 r else ' C( C% F9 w8 {! o Exist=false; // 是目录,目录不存在 4 w: T& R8 B6 b7 B$ K FindClose(hFind); . ?% n9 y( v6 P/ L* R; G7 P& Z}

$ f# _; G8 a, E0 P

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

, s' j+ B, u9 |+ m# d/ m3 G5 }

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

1 K7 Q3 Z% J1 b; Q6 r* m& y

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle ( O" S# r% O8 Y" a. a4 c$ s LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL ) s+ ^3 P4 M5 f f, q# _/ FLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 : ?" o+ ^9 P* QLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 8 s1 u! a0 R8 e v8 u+ A; T0 M UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS & P) Y# o5 n# k2 l+ v: ^/ M BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL ! ]7 Y6 G; A" n1 xLPARAM lParam; // 预定义的对话框传递给回调函数的值 # J$ d7 r$ k: pint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 1 V- k& J* H; K$ e2 p( ?可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 3 }( u+ i+ m: M5 ~, n" q#include <shlobj.h> // 必须包含的头文件- R8 [& H9 I4 P0 x' ^8 e6 l+ @ char SelectedDir[MAX_PATH]; // 最终结果) K8 ] I0 l$ }1 @8 b BROWSEINFO bi; // 入参 / L# L. `% T5 b; D2 ^char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font / I9 z( g4 t: W+ R0 X* x. w4 k4 }8 A LPITEMIDLIST ItemID; // 所选目录的系统标志指针

0 q, C3 Q/ K, \. D" E

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 : @ d8 R6 o4 n6 lmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据/ @! e$ s" H& W) | bi.hwndOwner = Application->Handle;9 i2 c: M+ D( p& ~. _# g bi.pszDisplayName = FolderName; # R. G( P6 d5 I Ibi.lpszTitle = "请选择目录"; // 改成自己希望的 ! k# b- W1 j# x& y& X3 Cbi.ulFlags=BIF_RETURNONLYFSDIRS; ! V& S# k7 Y( R0 }+ X% [ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 : w1 E5 o3 j" J' ]5 n# a6 ?" yif(ItemID), z+ G: E: G J- y- H( k& [ {& b5 }: N# L4 H SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名" a# |& T$ |- `3 R3 ]0 k! | GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 ' A) F6 d: X/ F/ T( }' a}

2 n+ S, v( b7 V) T) x/ Q

三、直接建立多级目录:

1 I0 c1 c# _& h2 o( m2 |$ Q

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

; y- Q3 |$ W+ n; e3 v$ w" R

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" + N9 A( b) P( Y: Q{/ P! P9 A& B) F+ m+ j if(P.IsEmpty())return false;* O# i7 _- g% i2 V5 `* J8 N% n int len=P.Length(); ; ?) F* o- ~$ n+ S* z7 o char *Path=P.c_str();2 e3 e1 d) R; Z3 l7 w" [& ]% ~ if(Path[len-1]=='\\')* k& A9 B3 a: _, [* K/ L0 b0 a { : o4 o5 M. j* d% k, c7 r" D len--; * t8 Z& B9 {5 Z0 w& r3 w Path[len]='\0'; 9 l0 w! ?2 I4 U. | E } // 删除末尾的"\" ( ~# W0 X T2 t* p* R1 e, C: Y( g AnsiString Dir=Path; . D2 k# i' F; b1 O/ n) H // 分开父目录和本身目录名称 ; Y1 R( e0 i* A: z AnsiString Parent;5 [! }% U; O; U+ J6 a for(int i=len-1;i>0;i--)# q H$ s( e/ @2 e; r7 ` T5 z5 | {! q m! e0 e( _' ^& L if(Dir.IsPathDelimiter(i)) ' ?: L6 H" \6 _9 ]5 { {1 A4 A8 a, {# i' [9 U5 ]$ q- J7 t Parent=Dir.SubString(0,i);+ K7 \) [" [. i0 ` break;1 x0 r0 v( i- E, k; C L } 1 ]5 G2 f' ^! f [ } ( S# w0 g( Z. M1 d if(Parent.IsEmpty())return false; // 目录名称错误$ B' [) R, P* `# U( x2 @& u3 f. N bool Ret=true; : } S% `2 V; s. n% b9 w& ~9 h if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录1 a: u% q2 C+ K( w% a+ Y! @4 ] Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在5 n% l5 _) N% o! p5 _ if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录% y8 N& C& f4 X7 K1 O( @( k' Q if(Ret) // 父目录存在,直接创建目录 ( N( L4 o. A& \2 F+ V: m0 r {7 W$ u4 Y: M" x6 e" e7 R$ E! W: w SECURITY_ATTRIBUTES sa; 5 i, z( n1 U1 R) h: w/ h sa.nLength=sizeof(SECURITY_ATTRIBUTES); n6 @& D3 t. r& b) z* ?" C+ S7 { sa.lpSecurityDescriptor=NULL;3 _- x4 `) q) S" f ~, D sa.bInheritHandle=0; 6 f" h. P# e: n4 n5 u Ret=CreateDirectory(Path,&sa);% q( I' r% I0 n. f0 S% M }; h+ j- T) Y; w# u4 z6 d return Ret; # z# B9 l; l4 J3 a} / G; `6 f) _0 M6 i% N/ h 可以看出基本方法是: + v' p& m2 z. O, @ A先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; + t& g @$ t( \ e* L 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

1 o" T+ E7 k5 }1 _1 K' P9 m4 m# v

1 ^; q; I; t9 m, R! o/ m 四、直接删除整个目录:

7 k& B% h' H( w& J* }6 g2 C

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

2 Z0 n+ _* s7 Q+ X( C( N

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) / A$ W3 d Q- n5 n# }4 R5 u 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 4 q3 {' ^. L3 W1 N如果找到目录,则进行自我调用,即开始递归过程。 ; M$ A8 v. u: t如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 , d# A2 e4 S; Q1 v 具体程序代码如下:

, r/ B" g+ P) S1 d' K

bool DeleteDirectoryEx(const AnsiString &) 1 i3 k' `. t9 N/ P7 Z$ @ D{ . k) q. k+ m* ? if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 ; t r; N# k. L# e* Z3 r+ P int len=P.Length(); 1 b) ~. E- q1 E- v( I! s2 @ char *Path=P.c_str(); ' G: |* E& [8 L. X4 A: \ AnsiString Dir=Path;4 Z' j- m4 A5 w1 B8 j if(Path[len-1]!='\\')Dir=Dir+'\\'; 3 j8 c/ E8 h( B* x& v' `! q AnsiString Files=Dir+"*.*";* X f9 f6 [7 f( Z$ P+ n: v9 Y WIN32_FIND_DATA wfd;/ J( I0 C% H+ M! Z HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 2 h! n9 a) k! m( R+ _ bool Ret=true; & M9 r$ I% N+ M( `" \* ?) P* J AnsiString Tmp;5 W. a! z* W+ `# Q( T, w if(hFind!=INVALID_HANDLE_VALUE) ( B: S6 G( h/ h5 e, D# D# h! E {1 J$ t! X; p) B/ U! g, N/ C bool bFind=true; 0 J' e$ `' r( l" }( F' H while(bFind)" ^3 y) M% ^* c9 h# d {6 n. @6 k! a9 N @ if(wfd.cFileName[0]!='.') // . ..1 g$ p4 B4 K( f0 z E { - V9 L8 `# f4 l: Y% i Tmp=Dir+wfd.cFileName;8 s- j9 D. t: p- \, k) m if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); \, x* T2 e6 o" ?/ F { // 删除所有子目录 ) @- ~3 |- }7 a Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);( g0 R' J, t$ y. `/ p }else5 V! u2 ~% l1 I9 Z { // 删除所有文件 7 l3 S4 a* v$ t' M' B N# O8 d SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);2 x4 V& w* d; J' R! m- e* q# y Ret=Ret&&DeleteFile(Tmp.c_str());8 T/ Y. k( d3 n. m9 D } ; H7 j$ G. ^, S8 J5 U } $ C5 q/ N% E7 n bFind=FindNextFile(hFind,&wfd);8 [) v, n, ` u2 ]: b( s } 8 v% @1 s9 @( c% y0 Y! a# F- h FindClose(hFind);* e) I3 r$ @* k: \) d1 g: f2 \ } 2 Z+ U( M, w7 [) x& Q, J7 w' Y if(Ret)return RemoveDirectory(Path);0 u( K$ [/ C' b- h6 K0 H return false; & I' z8 S6 Z+ G% I: c$ D) {} / K9 i/ T" ?$ v. c* _. m4 t! S

% B$ f4 C i2 _" k* i9 q. Y9 ]& M& {

9 M( `7 q8 j: [0 G) p; S0 Q2 o

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-7-15 04:36 , Processed in 0.509094 second(s), 53 queries .

回顶部