QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

: H5 `: E! k5 _& U0 ?! A

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

" x: ?) ^1 u+ A/ N

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

8 K; t3 {- {; V

一、判断目录是否存在:

. y$ F: y9 Q' f8 \( Q- _

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

9 M% \) x$ b8 F l4 q

设char *Dir为带判断的目录( h' s; z' o7 S% |* K3 E! ? bool Exist; // 最后结果,表示目录是否存在 0 T9 ~/ B9 H4 x, l% G( i1 lif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”6 x0 N1 }; Z5 @2 o& j1 _ WIN32_FIND_DATA wfd; // 查找4 u2 n1 V# p. F* Y! x1 ` HANDLE hFind=FindFirstFile(Dir,&wfd); " e$ w' P) r( kif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在2 h+ [3 X2 A6 o9 q$ x else # b/ u( F# D! {0 A+ j% x3 g{. l4 a2 d0 b6 l2 V if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录) m2 u! }7 R2 f' b( b1 ~% i Exist=true; // 是目录,目录存在 7 h/ \" O1 }4 C4 `8 i else - P. u9 S3 q' @; d% V+ ~ Exist=false; // 是目录,目录不存在 $ Y" a" V3 \6 w) t7 n; x FindClose(hFind);# S; k# `, e3 [5 F }

6 O. a7 @/ k4 r# ^ z+ }* K

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

6 z9 N& t$ u9 R8 I) d$ m7 B

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

2 O1 p; s, G* J- x

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 9 ^8 Q7 D' o; a: ?9 ?0 f LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL ! T H$ N! X+ B4 F9 X% m, T' d2 BLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 0 N; X" f5 d) c8 i+ x% Q LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 ; A+ x% @4 C, s* C5 F9 s UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS $ g6 n$ n, B# ` BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL : I7 F+ P! f+ P5 Q7 E% |+ t LPARAM lParam; // 预定义的对话框传递给回调函数的值 2 Z n9 x2 B' e) gint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 / { \* J! s1 `* r8 U( h- ?; A& i% C可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 1 J. f4 S" E; a; C#include <shlobj.h> // 必须包含的头文件; n+ ~6 H/ G' d- s% L7 m5 t1 ] char SelectedDir[MAX_PATH]; // 最终结果5 g! b$ X3 W5 S, \1 e+ C BROWSEINFO bi; // 入参 8 l' N9 @: D- M0 Dchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font 0 K! n) s9 x1 k& v LPITEMIDLIST ItemID; // 所选目录的系统标志指针

. s: W" D' }- O8 I

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果' z. ]7 M Y+ \! W+ H/ s; o memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 ^( Q X4 s, [3 ?! Ybi.hwndOwner = Application->Handle; 6 X+ j; N2 }. ]* Bbi.pszDisplayName = FolderName;+ P" A: E0 W. G/ k bi.lpszTitle = "请选择目录"; // 改成自己希望的 9 ^7 ^, j& B$ Q1 K. _bi.ulFlags=BIF_RETURNONLYFSDIRS;$ x! J% L# a$ C8 J7 b9 O' x( Y ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框7 J( T- B+ x* S' X# t- B if(ItemID) ; G6 |7 b, g& R6 A3 {- m{/ b2 e3 U$ X, f SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名& K+ `0 V! x" U& i GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 7 a0 V8 G1 c& D# [}

$ x% G4 i4 I# h1 M" X0 m

三、直接建立多级目录:

2 [! s. ~1 o% T$ |

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

! ?, g) S# X. J1 L6 N; X

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"4 k$ ~0 `8 B7 ]5 }- U( L/ K# i* w' V {7 q- j% |: F2 p7 \4 x: X- l if(P.IsEmpty())return false;* a p6 }" e* z/ Y int len=P.Length();+ q; K/ \0 `. G4 K char *Path=P.c_str();+ P5 E8 ^$ u9 |# W if(Path[len-1]=='\\') 1 S1 p( \$ M* c8 {* \8 m% f {" y. l7 t& w; o; h" R len--; ! O+ }. }% _' A$ M* D" f1 v Path[len]='\0';; r4 j7 r& B' z } // 删除末尾的"\"1 S, `: u+ C3 f2 Q* [3 ]; X AnsiString Dir=Path; & P* W2 @% O+ I: v // 分开父目录和本身目录名称 ' m! u; u9 q" g9 v' D% b! S& g* ? AnsiString Parent; , t; k; P3 J0 v8 a0 S: S# c for(int i=len-1;i>0;i--) / a5 B" Q/ J: W5 N+ H! v/ X0 o/ u0 t { 8 t# j0 c5 ^' E4 |$ C+ m$ ?, H if(Dir.IsPathDelimiter(i))# V$ L" e- y6 U- E4 y6 `) F3 K { - e( A, ]4 u7 {& w( y8 p Parent=Dir.SubString(0,i);; Y- t& u# ^5 [$ L break; % ^4 b/ b. I5 P; Q } / {5 k1 u) j; K1 L } 9 b9 R" _/ ~% ^ if(Parent.IsEmpty())return false; // 目录名称错误 0 S3 T$ A' _ ]0 P' h7 z bool Ret=true; 4 c. p5 A' x/ O5 R. ~ Y if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 + G+ H8 N% ~2 v, w Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 " n) v+ U; u k8 V if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录% m' K# M5 l+ i% e7 s) w if(Ret) // 父目录存在,直接创建目录 4 B; r0 `/ @* `2 O {# N. O8 k T+ s; I+ | v9 R% S SECURITY_ATTRIBUTES sa;7 a3 M% z5 e( J sa.nLength=sizeof(SECURITY_ATTRIBUTES);9 @' {" v% P1 h3 w8 G0 b sa.lpSecurityDescriptor=NULL; ' w( n; C. e6 d) Y8 y3 B sa.bInheritHandle=0; , b9 V2 \) B" o* A$ F& t Ret=CreateDirectory(Path,&sa);& j! P# @6 u0 b) ~ } 0 u3 x' O$ _0 t' ~* r+ b return Ret;9 ?, E% f/ W1 V) m1 I% ~7 b' _ } * E5 q! R( s$ d8 r5 Q4 t1 n2 g { 可以看出基本方法是:, a8 G& ?$ @6 i" s$ b 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; + w" f6 R; ~. U' B; M# P* u 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

4 W; w% G+ N* Q) g& z; Z. K7 E

0 U9 b' H$ `/ H2 _9 A四、直接删除整个目录:

2 |6 S/ o, A: l8 G2 }) {" p. X! g

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

) `7 b# g$ M4 z5 f

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 2 g( V& c! H: ~ 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 0 d1 q* C, v& O6 Y, v2 J$ s如果找到目录,则进行自我调用,即开始递归过程。 ' C" @. S# K! j3 Z% h( j. s如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 / b, `- n( a) {% n$ ~: \7 }8 [具体程序代码如下:

! x) g" y+ Y0 ~+ L

bool DeleteDirectoryEx(const AnsiString &)* R! A4 S$ C- E: K; f% I {' M1 x2 k/ p B) M) [ if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白2 m# p# p U2 I6 q3 b1 O7 [7 q' v int len=P.Length(); " o9 \. ~, e& I0 q$ a# m1 u9 G char *Path=P.c_str();; q3 Q7 N- {2 z. u# j* V' ~3 Y AnsiString Dir=Path; , g( I% i7 a+ \* {" ]2 M' S+ L( a if(Path[len-1]!='\\')Dir=Dir+'\\'; \5 b; X8 R5 v( }7 o" n AnsiString Files=Dir+"*.*";5 d( m9 ^5 f7 g WIN32_FIND_DATA wfd; 7 u2 l7 f0 Z( x) v+ Y HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); : E: e! b8 y4 d; X# T6 F bool Ret=true; 1 Y; c8 y3 M0 ]# N1 t' e AnsiString Tmp;- X' R: N- r7 G# \ if(hFind!=INVALID_HANDLE_VALUE)8 M# b) D; y* |1 A" R+ g7 X- o) ?0 a {# f7 S( }' y' ~7 Y bool bFind=true; - @. d, l; ^0 H. F' @, u while(bFind)) a! H; s( q, J0 C v8 B2 } { : b, [! {2 q1 V9 B' }, u" g if(wfd.cFileName[0]!='.') // . .. 8 G: j, ` Y" ?4 @7 E { ) U' H0 f9 {& j2 w8 L3 _" @ Tmp=Dir+wfd.cFileName;+ L+ b5 T" q$ I U1 i; ~3 S$ ^ if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) \! r2 ~$ p2 m) D { // 删除所有子目录 2 w. o. K1 }7 N* k3 o3 ` Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); ( j9 S c: \1 m2 z" k }else 2 V* z) V) a9 W% D, g& A* b- P { // 删除所有文件 7 i+ _# C* H, g, a5 H3 o SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);+ q L9 A, d+ f$ p, w1 H Ret=Ret&&DeleteFile(Tmp.c_str());# j# n- m: h. m: @& A9 a }6 c9 S' k K1 F } ) ~* v, M! ?2 M" R @ bFind=FindNextFile(hFind,&wfd);/ I8 D6 L/ P6 T ?8 O! \ }! g0 x4 V2 s+ _6 n7 L FindClose(hFind);* k9 [5 W$ g {, K } 0 ~4 ^' o$ S5 H7 D if(Ret)return RemoveDirectory(Path); . ^: z1 a) d) u! }- p% w+ p return false;9 ~' v6 E% ~- H+ {/ D( u2 ^ p } % k8 K- s, J) \: _" h* v

9 ~9 a! _; \ ~6 N, P

) B$ V. ^1 H! F' X$ g7 s0 r. B

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-4-20 23:21 , Processed in 0.535106 second(s), 52 queries .

回顶部