QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

! n) P4 v6 \9 d' O

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

' [% D7 a/ j+ E

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

1 Y( e5 e$ c* m+ `8 {

一、判断目录是否存在:

" i3 u% k+ |7 Z

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

2 Q" t2 x/ i9 E0 R& L V) J9 R9 V

设char *Dir为带判断的目录% N' `! j6 l- M8 R& [1 E bool Exist; // 最后结果,表示目录是否存在 $ y5 x5 Y. C$ A% g8 S* [+ M0 Pif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”5 x3 x4 G* h( l) Q) x WIN32_FIND_DATA wfd; // 查找# Y/ w4 s, Q2 c; H" W4 @8 a HANDLE hFind=FindFirstFile(Dir,&wfd); 8 \+ y: y8 V8 C$ B0 o4 d6 J if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 $ [- c6 r' O+ V. n4 ielse3 Q) `6 [5 x! L* G8 _8 t+ M6 y `3 C {0 W5 x/ N* Q' i6 Y; }, B if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录, |4 z: x A! @7 ]: ]% D A Exist=true; // 是目录,目录存在- k$ h: W) H- ~; J. H7 I else 7 x. b2 H4 @8 D. L2 r4 h9 m Exist=false; // 是目录,目录不存在: @4 R4 A8 t* n( h5 I6 y& b FindClose(hFind); % g& _* [/ X0 Y# Q) _8 B( E- E4 ~}

% T8 w( K7 R* [# E+ Q6 r/ [/ l' y

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

' i" p; n! u" y t @

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

) Q- @+ M& M, ]

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle ! ~4 { i# M) w/ a6 ]LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL R* E) }$ M0 c4 ~, N1 j LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 . k+ c: N4 `2 v6 [+ _# x% c LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 6 g3 j s2 a' m0 {1 J8 Q6 {5 zUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS * R7 `6 Y3 N$ Y+ ?- ]: {8 r0 b) MBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 3 g4 t I8 B4 b6 yLPARAM lParam; // 预定义的对话框传递给回调函数的值, P, V. W; {3 X$ e) Z! ?+ x3 \# }/ M int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 $ V+ R+ U% A1 J2 K可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: " g. ]) } |& ~5 c3 p #include <shlobj.h> // 必须包含的头文件; I o8 Q$ q( B9 {' s char SelectedDir[MAX_PATH]; // 最终结果- U& T5 ]1 o$ A& i( S/ O BROWSEINFO bi; // 入参4 h( N6 c2 D1 _2 ^# n char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font . e& x/ R5 D! ]8 E, F9 |LPITEMIDLIST ItemID; // 所选目录的系统标志指针

5 X% b- J/ {. n& @6 w" |

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果2 v& k+ c" [8 s, E* P) C memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据/ o/ a- E+ I# |$ w7 p5 @6 j0 Z5 B bi.hwndOwner = Application->Handle;0 ?2 G: p# j# q. ], w- G8 e bi.pszDisplayName = FolderName;3 R% A2 r/ d5 E9 d bi.lpszTitle = "请选择目录"; // 改成自己希望的 # A/ F0 O, _' @5 a, N5 o, }4 @1 q' Pbi.ulFlags=BIF_RETURNONLYFSDIRS;2 f- r2 k2 w6 S% r' m ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 ( [+ \8 k: X2 e9 P2 p2 ]+ x1 n jif(ItemID) E2 @7 M& Y _{9 ~/ o8 v0 d5 |5 s8 Q) e; A SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名- z+ v1 l( a" W; g% Q GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 - j' A6 g4 o, `7 _% ^3 \}

5 I* f2 @! r& e. m8 T+ n5 A

三、直接建立多级目录:

5 i4 k w X* R. } R8 G6 G

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

7 i3 b% j, a3 M1 q& `1 k

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"7 G* l" n$ D* D( l; T) W" x, T { W9 l; D; C5 F9 m9 d if(P.IsEmpty())return false; ; s4 o! `2 }, E/ M0 M" E int len=P.Length(); 8 @$ Q2 i' t* A' S T; [ char *Path=P.c_str(); 3 G W+ j* Y+ F0 ~: Z2 y) s if(Path[len-1]=='\\')4 @: _& F5 O% @& J {7 U3 @7 G) Y' U& Z! w( |7 v len--; 3 S$ D% a6 U/ A2 x" j1 ^$ u1 u Path[len]='\0';3 x# ^( J, ~; n- a$ e0 U } // 删除末尾的"\" ) g8 l2 I& G/ @6 a" [8 R AnsiString Dir=Path;; L) _( V# H6 E // 分开父目录和本身目录名称 1 O# g8 f$ F, L0 i# \$ l+ K AnsiString Parent; 1 R( N) ?* V7 f ]1 {! K; @" D. m for(int i=len-1;i>0;i--) $ F1 P7 @" _. E% j8 A% N {- a1 x! c- r9 E8 _# ? if(Dir.IsPathDelimiter(i)) , i d4 W/ B9 C# a" f3 v/ K& v { ; s- n" A, |2 x3 K# f' \- s Parent=Dir.SubString(0,i); 6 e7 |* n( L K- C" d6 q break; - a9 m; k5 W' e; ^! k } ) m# Q9 B3 a+ a1 _3 Q; \8 @ }$ C4 }; A+ P9 D& P if(Parent.IsEmpty())return false; // 目录名称错误% z+ F1 W: D! J+ |! U: g' w# a( y bool Ret=true;$ V) [9 s% |5 d: ? if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录+ d7 n8 w1 j" S0 K+ X Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 2 v$ v- R$ l+ B0 g if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录: F2 n6 {9 s9 y( p/ o if(Ret) // 父目录存在,直接创建目录3 L+ I: Z" E0 Q g( p. k( t3 A { ( k" O @; \: F0 s0 ?. Z+ x SECURITY_ATTRIBUTES sa; p- V$ r8 |2 v- A: O! \/ ]7 p sa.nLength=sizeof(SECURITY_ATTRIBUTES); ; Z) O5 v ]! O+ s sa.lpSecurityDescriptor=NULL; # D/ d2 a h( T' k sa.bInheritHandle=0; & u9 l: j) S) _4 i9 s Ret=CreateDirectory(Path,&sa);, c8 z8 F; H) Q4 H; P }: l5 _6 y' M( z- ^% p) E return Ret; 1 ]/ I2 ]4 a' d6 l4 k2 n} 7 I2 J6 H) {0 _8 H: E& ~ 可以看出基本方法是:3 @$ t) x/ [, q0 Q% V! \- O 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; $ P! J. a! b( I% T 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

6 u n$ h/ }1 p( \7 s* y

. c9 S( n. @2 w3 w' o: I( ` 四、直接删除整个目录:

" d2 ?3 } M, B3 n

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

* B- ^4 i2 b+ |! S0 v

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) / P$ U" V" a! O" \. C O如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 % p# n" \/ P4 l D5 Q9 ~如果找到目录,则进行自我调用,即开始递归过程。 * S O6 k: D0 ]: u1 i; W1 | 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 * i7 w& r& _! N' y3 F. H5 f; n具体程序代码如下:

0 S3 v) D2 V& T) G0 g" l( L

bool DeleteDirectoryEx(const AnsiString &), X! I( \* T1 N* w$ i4 ~7 Q {" B( a9 w1 D) U* E6 V: b if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白% Y7 B! p- |6 m+ I int len=P.Length(); & q, Z: N+ i- P4 ^6 y! p char *Path=P.c_str();4 A9 u2 |9 h' m5 Q' E, Y& D AnsiString Dir=Path; ! t) I% b. J( {+ y if(Path[len-1]!='\\')Dir=Dir+'\\'; % h N8 M6 ]: _0 C' O AnsiString Files=Dir+"*.*"; 4 R9 Q F. t/ e4 M& @9 k WIN32_FIND_DATA wfd;7 b5 e1 t4 j+ ] v0 Q HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 8 m/ c7 _- w) [! H* c bool Ret=true; % w2 `2 e: z* @6 c AnsiString Tmp; 6 @; [" A: W: d. w if(hFind!=INVALID_HANDLE_VALUE) 9 a/ ?" q" o% e8 x6 e { 6 y" K- v" J9 H& t& h- b, y; h4 h bool bFind=true; , I) F& N/ F: A2 f. \% L while(bFind) 9 G, A) T( u# o3 `5 t0 p- K4 {8 F {( o7 q7 E" z. w/ [$ N5 k7 T if(wfd.cFileName[0]!='.') // . ..8 o7 b3 O( r) C% K) j1 m& j { - T: j5 N3 M6 l Tmp=Dir+wfd.cFileName;4 j& Q/ E# k9 ^' F1 j7 H4 [ if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 2 k: C, j; J+ a- d { // 删除所有子目录) L9 v: w Q, N3 e! M) A6 A! K Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); - d6 G! t6 l7 J) Q# D3 ~, y }else8 Q* w u r0 m+ ^7 G% k* L { // 删除所有文件 , O0 ^1 ^3 @/ [4 k% V2 N$ R( j SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);) u' x) p' N }4 b Z% o/ i5 t Ret=Ret&&DeleteFile(Tmp.c_str()); . T x( n* r$ n } ( K0 I" ^# p7 X8 P( g }; x; P a/ e1 t6 s bFind=FindNextFile(hFind,&wfd);9 s5 B) Q: U0 L9 B; o2 b" D1 m } - x+ J; ^, B+ N FindClose(hFind);9 c- _5 V* s' S9 |8 e } + g( l! s6 |5 l if(Ret)return RemoveDirectory(Path); : m7 ]; U4 v T3 P8 o: W return false;6 [4 }6 h% x/ N" z } R4 s% I# E2 V& J V6 {$ R

! A. F! w7 M+ d5 Y

% B" `/ E o8 j" N

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 17:21 , Processed in 0.471725 second(s), 52 queries .

回顶部