QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

% w/ _, q1 j9 ?3 X, v

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

$ ^. |/ m$ Z$ F+ T' Z) F

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

/ p& @% h' a& Z/ F% F

一、判断目录是否存在:

; q$ O- y, t `& t# s! ?( J' D8 c

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

; n" ^! m* A) c5 F3 }4 a

设char *Dir为带判断的目录 ; w6 [9 L+ _: l y6 Y+ u. Hbool Exist; // 最后结果,表示目录是否存在4 {% a' i H( U5 |8 g2 e U* F% W if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” 3 P+ f7 i" d/ NWIN32_FIND_DATA wfd; // 查找 - |2 B( p6 f! ?, v( LHANDLE hFind=FindFirstFile(Dir,&wfd); 5 S/ P a: |4 f3 M$ T2 ?" hif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在* Z. m, k ^& Y" l else) `# H! M/ h1 B8 c' w! J0 z {2 {4 U5 l& m# @) e" H" p1 F if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 3 Q$ V2 G- t0 |0 R+ K$ u Exist=true; // 是目录,目录存在! \* A& R, C: ^0 n/ g$ Q else 2 C6 {4 k) {: P0 r2 z7 e {- G8 P Exist=false; // 是目录,目录不存在0 T4 R. V' f7 o) _ Q FindClose(hFind);# Q) F; h1 @' A/ v# u6 O. V }

7 H2 \1 Q9 z- @8 u: V& t: S

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

& l W$ ]; w6 k9 g \9 f7 Q: R

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

3 r* F* i, m2 H8 F, _* V

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 9 G: M8 s! _& }6 w( |$ ?) F LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL6 T0 S2 o' ~; C; p* B! n3 M LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 2 T4 c( r3 T D: }& N. j LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 6 B9 k2 u* h% ~: f0 R* N0 K2 y/ f UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 6 i# u3 X( _4 C3 H* _" y) Q8 B BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 6 V) m2 `/ d( Z% LLPARAM lParam; // 预定义的对话框传递给回调函数的值1 C. e& q. @6 p U8 F/ E5 t int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 * J* I8 T! z: d, y1 l- i+ ?4 n3 L f 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 9 [5 r/ j9 }- p7 O9 V- ]# w* r #include <shlobj.h> // 必须包含的头文件 7 O( X# i7 J7 c5 X; H) K4 L1 lchar SelectedDir[MAX_PATH]; // 最终结果 1 `( X3 i: |2 L( N/ iBROWSEINFO bi; // 入参+ M& L9 b5 X! g* ~1 z char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font % m5 a, V* E$ n" g LPITEMIDLIST ItemID; // 所选目录的系统标志指针

# y/ U! Z7 c+ k! s$ N

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果2 c' @: ~! _" i: Q/ Y* H memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 1 `# E7 c* ]/ c) |$ L! x vbi.hwndOwner = Application->Handle;7 y/ v& W- Y: |1 ?, B9 ]8 b I bi.pszDisplayName = FolderName; # w: B, t* O/ e8 bbi.lpszTitle = "请选择目录"; // 改成自己希望的 ' v6 x9 h" o8 zbi.ulFlags=BIF_RETURNONLYFSDIRS;/ N! D) Y) n/ z% e# G4 i6 w ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 ! {0 A( I$ h Q/ w6 Cif(ItemID)$ Z+ D5 S# O. @! `9 J+ _# ^% J% U+ V {" v9 b. \2 w# {! w" c) } T SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名& I/ u9 W! K! [& w# c GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 % ~! |( z! M7 W}

3 [. ^* w* [! T- N% J# C4 X) o

三、直接建立多级目录:

- u5 u2 }+ r' r8 s# U7 _

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

1 j8 {! Z0 Z+ K# M H# x+ ?8 Q$ W

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" 8 G# ~: V7 h* h8 T4 c' P' b{ - ]' l, x3 [' \, ]2 s# n if(P.IsEmpty())return false; 7 J0 C7 z2 [) F! i! X: f: S6 G int len=P.Length();1 ]* U9 L* |9 P char *Path=P.c_str();: Q H: ]8 ^9 G3 m- P- G if(Path[len-1]=='\\')" f! m) l2 l$ X* g/ P+ |5 {0 k/ i { 1 n- @* D, e* ]6 V/ D2 U- ]4 k& v len--; # Y3 s8 N! S3 t1 w# n+ Z Path[len]='\0'; 5 x6 x8 |6 _0 x# V/ d. K* \0 @ } // 删除末尾的"\"1 Y0 C# B4 x) `4 a AnsiString Dir=Path; 1 ^- g8 y+ ]6 i3 A) D8 P- @; E2 X // 分开父目录和本身目录名称7 [ Z2 p* `- W- P7 G2 K AnsiString Parent;9 a2 {/ i8 ?% X9 {- g9 E4 P- {$ A9 @4 M for(int i=len-1;i>0;i--)$ m3 Y7 s4 `/ D5 M* t { ! N5 b( _/ E8 S# @( V if(Dir.IsPathDelimiter(i))2 x- @5 u6 D( O$ B {) ? B* d2 ~6 B2 m* t1 H, R1 Y6 ^ Parent=Dir.SubString(0,i);: T$ A' d9 x' v. u break; , O6 Z) b7 C4 }/ o1 u } - E; T3 R- D E: a( l/ @ }9 Q X8 E/ m3 p. S3 p0 e5 m6 r if(Parent.IsEmpty())return false; // 目录名称错误 " V5 ~3 Z% l1 u2 c0 Y4 c% h$ e2 [ bool Ret=true;2 m% Q0 r' h( _! R2 {# |( U ]3 B if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 0 Z0 T5 ?. l. ` R Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在0 e% B; R! P' T+ N9 R5 D7 U if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 B: v& x, {4 s; n. m if(Ret) // 父目录存在,直接创建目录4 R; {3 s% M* M( [ j% Z4 D: {. a' [ {' U3 W, p" i5 N7 N# s$ \% _# J. @ SECURITY_ATTRIBUTES sa;- T7 E) k1 F; |& Z% t( N3 Y sa.nLength=sizeof(SECURITY_ATTRIBUTES);1 a% K. }, U; E k3 w9 ` sa.lpSecurityDescriptor=NULL;; _; I2 L w: Y sa.bInheritHandle=0;& l0 B2 n1 P* z7 R8 Q Ret=CreateDirectory(Path,&sa); * ~0 P c* {5 ]+ {3 e }. `; }" e3 L7 h) \9 e' G" J return Ret; 9 n# L9 D0 {. _' @3 z4 \( `} 1 F9 J4 a4 d4 _0 ?" ` t# T 可以看出基本方法是:- f- ?$ K9 `8 r 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; + o/ E( K& Z0 t! M5 S$ Z/ F' R! @如果父目录存在,则直接创建目录,否则自我调用创建父目录。

' M7 E: R& i6 h8 E) \0 P1 w

9 b+ R% i* Y+ j. X4 K# i 四、直接删除整个目录:

: d2 o& @+ S2 Q% r6 j

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

; s e8 R2 p# m& L1 {, T

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) , `! Y# ~2 _6 Q: _. x0 t7 l 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 6 H+ Q3 c( A1 i 如果找到目录,则进行自我调用,即开始递归过程。 # h+ }9 p) k# E: d3 [ p如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 ! G8 {2 D" q; z( z% e# p具体程序代码如下:

4 v# F1 C7 Q) j2 U7 j: u

bool DeleteDirectoryEx(const AnsiString &); y6 t$ f9 U1 X2 W* q4 L { & l$ w' d4 g8 m1 e0 y, p if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 ; P" @) |3 \4 v* R4 u5 D int len=P.Length();- t' P1 z& z4 p) p8 |5 P char *Path=P.c_str(); f) d! r+ q% Z" w' b AnsiString Dir=Path;* I% L1 M3 V- T: Y8 ^3 X if(Path[len-1]!='\\')Dir=Dir+'\\'; ; F# K3 J0 y1 |5 J: O+ |% w8 l AnsiString Files=Dir+"*.*";8 ~# y9 n: d T/ }4 v7 M+ X+ V. f WIN32_FIND_DATA wfd; # M, K" \* h+ q2 Z* X HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);9 Z8 r5 I" H' l, ? bool Ret=true; 2 E2 [& N5 _6 t: ~ AnsiString Tmp;& ?6 e* S+ t- q# D if(hFind!=INVALID_HANDLE_VALUE)+ ^+ k& y0 z; {5 M { G2 X( w) @3 p- n( e bool bFind=true;$ p7 Y, b9 j0 \2 k while(bFind) 6 G6 j9 ~# z2 C; v {1 n% O9 J( z) m if(wfd.cFileName[0]!='.') // . .. 1 m- `! f4 ?+ W' a/ R. q8 |5 ? {" x" q( O6 z' _' ? Tmp=Dir+wfd.cFileName;6 i" {0 D) l+ I- n, f$ C if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)1 p, I( R: V0 c8 b8 Q& l+ l { // 删除所有子目录 # e: H( Z0 x' N7 U0 B Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);: I, \; X- B# [0 a1 {. p }else % S% f/ ]3 _! j7 X- m6 ]5 E { // 删除所有文件. I7 f! c& ]% Z9 G& U SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); , t/ ^6 M3 ?& x( U/ k% O9 q Ret=Ret&&DeleteFile(Tmp.c_str()); " P2 u) y% f+ u% G }* i1 M9 c! U1 v# { } # D/ I9 T$ T& `, B bFind=FindNextFile(hFind,&wfd);4 l' M3 P$ |$ Y1 m1 w. D } , d7 l2 \% J/ B9 h" ?" u FindClose(hFind);+ S0 j/ S, k4 {; Y } % P! s; R1 `. {7 I' O& C! S if(Ret)return RemoveDirectory(Path);8 z7 @# P' T6 Y- \: }8 n# p0 k return false; 6 e1 l$ M- k4 `$ @} $ x+ f3 Z* E( u2 r

! K% \( P4 ^- T* S7 p! L% I. |

! F6 y- c( q( C Y6 Y7 `

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-11-8 09:28 , Processed in 2.029617 second(s), 51 queries .

回顶部