QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

! C8 a6 t8 O7 T; L9 N3 X$ d: H

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

7 @4 L+ ?3 G1 J9 X$ n& f# [+ u" h

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

+ ?7 N% `0 z( P! D' c- F

一、判断目录是否存在:

9 G2 S- ?/ t5 b

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

& {! q0 ?' R: m: @! y I' U6 Y

设char *Dir为带判断的目录 0 h2 a4 A3 R( Fbool Exist; // 最后结果,表示目录是否存在3 U6 Q7 C7 C1 y" O if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”, Z% i* P4 ?3 T WIN32_FIND_DATA wfd; // 查找9 x0 [9 j8 ]( l5 w- {4 y( d HANDLE hFind=FindFirstFile(Dir,&wfd); 0 ~/ i$ E2 ]$ ]8 b( Aif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 6 \# @' X8 ?6 b- y$ j9 \) a5 }2 h; Velse8 |% I- w3 F4 E+ c1 R4 j {% }1 ]* A9 r7 K! [/ U% u) R9 R if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 , [" f0 f# [0 R) A Exist=true; // 是目录,目录存在 $ C% ?+ ~/ u7 F- C. U& k" y8 @0 J9 H, U else $ D: w0 o* g/ H% T; I) x. c Exist=false; // 是目录,目录不存在, I9 h* R# h z7 F5 ^% _: W FindClose(hFind);/ k! D' N0 Z. c/ }) N3 `) o }

% A) p5 u, F% `- a8 X$ B+ q

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

8 @) y# { ?# a

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

0 f: I1 h1 {" B8 G# `

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 5 @, _; s! b# e1 }# i: \ LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL" |" k! ?" Q8 e" G LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 5 m6 I: p' _/ Q$ m" h6 g; d) P LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 # N9 a8 D3 _7 G" I UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS ; W2 n% @5 Z2 y$ [ BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL # J. U6 l4 R9 l! g6 pLPARAM lParam; // 预定义的对话框传递给回调函数的值, ]9 W5 G" C8 ?4 y5 V8 Y6 X, ~5 ]* N int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 # p, q5 m3 \9 y- w0 G c9 z, M可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: ( T( r9 z/ R: ~$ I5 g#include <shlobj.h> // 必须包含的头文件) \# l+ V( o* }8 B; A) O char SelectedDir[MAX_PATH]; // 最终结果& n% N$ F- U2 `5 v, L BROWSEINFO bi; // 入参 ' M# E+ o, ?# |" B% N; bchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font * y7 o0 ^9 ~/ W: X1 iLPITEMIDLIST ItemID; // 所选目录的系统标志指针

( N; W+ X! l7 n5 q

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果. Y+ M0 Q) ?+ Q* o( J/ p memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据/ C0 {. {8 S' o6 u" U bi.hwndOwner = Application->Handle; 3 H" D9 W8 X+ H: u( |bi.pszDisplayName = FolderName;2 T6 X+ I) X/ c) S bi.lpszTitle = "请选择目录"; // 改成自己希望的: D1 v2 W! [, H* u8 a bi.ulFlags=BIF_RETURNONLYFSDIRS; . u0 t2 A6 q0 m$ V {* bItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框3 b1 h' O+ y; y- d) @- r if(ItemID)1 \0 w! P4 o4 a; r {& O( L: ~; H; A3 J" a SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 $ S7 t! S$ f" X% j, `/ m9 r- s GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 6 I$ j. A& L+ x t}

7 Z& U) }2 P; C7 I% s

三、直接建立多级目录:

i: V+ K z1 v: m p- q

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

4 N' V& Y3 o6 h" _; y0 M

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"- ?) I6 Q$ ]" y) t# ~: @ {5 ~$ ^- ~) n) h8 |, ^" l: L5 R: ~6 J- k if(P.IsEmpty())return false; 3 _) k5 j g5 }0 F0 w int len=P.Length(); 6 I) M4 W P% S( w0 ~8 x# e$ ~0 b char *Path=P.c_str();. |8 s7 D/ I& |% ~" s if(Path[len-1]=='\\') * N8 U9 t# ~* r/ u, T { 9 Q* [( i0 O& S i# K! |/ d len--; ) S- r. Z6 i- _( d+ ~! H) H Path[len]='\0';. U3 E2 Z7 |# A! u } // 删除末尾的"\" ' L0 F2 Q4 Z R1 p" { AnsiString Dir=Path; 7 u: v3 f9 n$ A" j( P // 分开父目录和本身目录名称 * v" R( u% Y# N+ h- K AnsiString Parent;3 `1 @3 J/ v" _8 z( ^ for(int i=len-1;i>0;i--)# ?! i/ [3 B, H7 u {! i+ z% j+ B# c* {1 I if(Dir.IsPathDelimiter(i)). L6 _5 @, j H2 ~' | { W8 H" g1 l9 c5 v! y) m0 Y7 z; B Parent=Dir.SubString(0,i); 5 A8 D! g$ T; V& K- j9 T# X+ u! e( B' j break;" f* ^0 a M( l4 ]5 z } 3 a% n7 \9 K- s9 O4 f, t* ` }; e! j# O, x/ g9 H8 m if(Parent.IsEmpty())return false; // 目录名称错误" M2 |% Y, l6 x7 \ bool Ret=true; - z8 H8 S) O ?( ]: b if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 & D$ D4 U K% c$ j Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 % p; v/ d, k) r/ h2 f) c if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 2 Z& v1 c4 W' N( l1 G7 E if(Ret) // 父目录存在,直接创建目录 - K* o& ~4 y" t4 N4 O, |) d; _ { " ^! M+ w* s3 p- c# _4 U$ E SECURITY_ATTRIBUTES sa;5 k& `( i3 _3 Z; P/ [; | sa.nLength=sizeof(SECURITY_ATTRIBUTES);5 S( S- T) U4 P( f& |! _ sa.lpSecurityDescriptor=NULL;, D1 E: g% `6 d+ r* n t H% M sa.bInheritHandle=0; |' X" A/ P* t% B% S5 k. a Ret=CreateDirectory(Path,&sa);9 Z% K& h3 X; E" O' a& K4 s. @( T: ^ } ; R. Z4 b4 @# b1 a return Ret; : a+ {$ j( p& | ~, F} " _5 m) B5 `! k8 l 可以看出基本方法是: c- ?. \- f9 q6 ~6 I 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; " m5 k. q$ @; c: Q, D) d0 V如果父目录存在,则直接创建目录,否则自我调用创建父目录。

# P) Z- d( k4 S6 x3 V3 w- g

' H" R, S9 \ t, } 四、直接删除整个目录:

1 H. O: i D; Q- M

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

5 X1 w" V7 c% `/ X( E* O' E

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 6 K R: D) z+ P3 h如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 " n1 t& m+ Z7 E6 `) R如果找到目录,则进行自我调用,即开始递归过程。 # k" |* K2 ?: l# d+ ~! S& o7 \ 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 - j+ V' I5 ^9 F6 e# b具体程序代码如下:

) g( V2 q( d( I) b p; d

bool DeleteDirectoryEx(const AnsiString &)# W. n d r/ x3 r3 ] ] { : u( I8 E. T1 I+ z; \ if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 1 z' x0 T* C. @, g0 S int len=P.Length(); ' O; V5 p1 p: J; W9 X2 {: I char *Path=P.c_str();' G3 T% D; ]* V: D% \; B AnsiString Dir=Path; 3 x8 o2 t7 Q7 ^0 x if(Path[len-1]!='\\')Dir=Dir+'\\'; ; U+ J" F% V& {$ q8 v, t# b AnsiString Files=Dir+"*.*";4 t" V9 _* p* _5 e0 r WIN32_FIND_DATA wfd;9 \& }3 v+ u; z' { HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 2 ]8 @; @5 C! A$ d2 ]4 w- A bool Ret=true;2 q U1 w5 h$ Q. B; h2 P AnsiString Tmp;! p2 h) z4 H# |, i6 e, b if(hFind!=INVALID_HANDLE_VALUE) ( c) K" b' X( i {# C. K3 v8 h- \& \( t bool bFind=true;; j$ j2 k4 H1 g1 b6 `# d while(bFind) : x. g; h" f+ ` { * F8 B8 ~! H0 a3 | if(wfd.cFileName[0]!='.') // . .. 0 M% S8 h) i$ j8 i+ X# g {& E6 [* |2 T* ?* m! u/ } Tmp=Dir+wfd.cFileName;& n/ N4 w$ F* e" a! s" R( O if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)" P+ k @4 a1 X- ~* J1 f8 W { // 删除所有子目录 9 K2 H4 h' Z4 N& _8 q# ?% a Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); 0 ?+ |5 z6 R# b, ^ }else . A3 U, s% r6 i, ^7 z# j# h7 \* O9 a- h { // 删除所有文件( E6 s% r6 d, I0 U+ h SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); ! C2 P) ]$ P6 s: b0 ]+ N Ret=Ret&&DeleteFile(Tmp.c_str()); 9 q) `4 s. B% C* }" J" h }6 }+ V, O) t: p/ ~% F } 7 b* b; @9 I4 {( E8 `7 l bFind=FindNextFile(hFind,&wfd); . x- n. I; N, ` } |" Q- s- |0 V U FindClose(hFind);% p. i8 s o6 v } 8 t8 }/ {. T3 u1 f! O if(Ret)return RemoveDirectory(Path);6 B: Q2 r l W3 @2 n U+ U return false; 6 U' r# t# l0 X: \' ?: l; t1 e) e} 7 A6 T' m, }9 O8 Z" b& F; g

! c1 k8 J& T; @+ \- N

& k1 c) L- s( J, S

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-6-19 05:42 , Processed in 0.390244 second(s), 51 queries .

回顶部