QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

+ D4 X$ J: b' d9 @, ?. P

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

; R; B, B. ^% i% F

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

9 }; f. }: X& O a e' H

一、判断目录是否存在:

' w* q9 F& |: U* r

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

a/ P" m2 r: B6 b3 @5 R7 @! K

设char *Dir为带判断的目录; W& P9 L7 z, p* {; ] bool Exist; // 最后结果,表示目录是否存在 5 G- Z5 z+ D: U1 }1 o( }if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” 5 \0 f5 j$ g# |) l9 V' {/ X4 [WIN32_FIND_DATA wfd; // 查找 0 m! T0 n! V% s6 U. g( @3 qHANDLE hFind=FindFirstFile(Dir,&wfd); 4 q( H1 F f8 O# o# {8 g8 v! Uif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 3 u3 U5 c" O7 T: S3 ?: gelse) b/ ~; i' o6 d# U4 k. s$ A1 ]* H { . D" p9 J2 Y+ `; L& a/ E if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 , H* l' B O5 G" J l Exist=true; // 是目录,目录存在( w3 H& Q- `; n else # [: j! [7 x$ c7 B: l0 c* ^ Exist=false; // 是目录,目录不存在 " B6 i5 E" e+ x0 g FindClose(hFind); & F7 c# U. V a# ]! E}

& p- s: D; k/ P, t. I+ K

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

, l4 t2 S1 G z" P

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

; N0 {9 K m* J" V/ g9 ]

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle ! h( C& N+ U1 x% t K3 A/ ]LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL$ u3 P0 D' [+ E4 ? LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 ) O: ?: W9 {5 y) Z/ }+ }4 C/ A LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 , s0 F( Y8 `7 G UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 3 M% a: K1 y; ^) a( f; I8 Y& WBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL # z( B/ l% U8 j& V9 {LPARAM lParam; // 预定义的对话框传递给回调函数的值 % N* ?# z" G& {) G) k2 P7 X" iint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 6 L, Y7 w: K: y2 F8 @. r4 v可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 8 K; g7 G1 F1 Y1 O* u0 Z7 M#include <shlobj.h> // 必须包含的头文件4 s$ }, N: {, j4 N) E0 q char SelectedDir[MAX_PATH]; // 最终结果 2 X' z; D1 ~$ @, V1 Y! _BROWSEINFO bi; // 入参 2 z5 A. s( |" kchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font 3 o" ]# t$ f& ~* J/ E. a: wLPITEMIDLIST ItemID; // 所选目录的系统标志指针

3 k2 H" n* A% N

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 8 T. u4 J+ h9 y' @memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据( n8 `" b, M1 T" i8 E) J4 u bi.hwndOwner = Application->Handle;8 N" T T' b2 ~+ D bi.pszDisplayName = FolderName;; A$ k5 h8 \% f( F- z6 x5 E ? bi.lpszTitle = "请选择目录"; // 改成自己希望的 7 A/ ]& O# j" D( Ebi.ulFlags=BIF_RETURNONLYFSDIRS;; b" \) x k7 v4 q2 F5 F ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 8 G. j: T( e# o! n2 T+ Wif(ItemID). q) G7 ~% y' y. S5 J( T1 ?: k {4 G2 X* z* V. J5 | SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 $ {- [( y C) @6 H) ?/ [+ ? GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放5 x$ u1 t0 l" A( o* w }

! A$ Q6 j, W1 f; d Y+ @

三、直接建立多级目录:

6 q9 ^' S' d/ J1 A; m7 f

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

$ ~9 h9 K& l' i" E

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"" i; y8 X7 b. B( i {5 J8 [% `+ {. R/ u+ k if(P.IsEmpty())return false; S K# K b8 I7 e int len=P.Length(); : ^2 m W, i( _ char *Path=P.c_str();, K4 c7 t1 i3 t" b" G3 H# t if(Path[len-1]=='\\'). \5 @9 z, l$ ?+ B$ n {, V: C- i) s+ r! m0 k len--;. U W$ \- _* y) i4 E( R5 J Path[len]='\0';+ s6 t" _( G0 h2 z3 s } // 删除末尾的"\" % F8 e: o/ l; E. N AnsiString Dir=Path; 9 O5 p- _4 o' ]- W: p // 分开父目录和本身目录名称 , v! M" [ Z+ g% N AnsiString Parent; % d- o. s; C" ~" B8 ~" r for(int i=len-1;i>0;i--) 0 E& N6 R3 f* u4 b& s8 ? { : R8 t* [. L# e* R0 B if(Dir.IsPathDelimiter(i))8 y+ B' `) G4 K/ T8 H y. R {- s0 T) M! d! S) x- ~9 m5 A Parent=Dir.SubString(0,i); / G9 w9 \3 F0 p break; : r4 ?* v# o# d3 U V$ r6 A7 h }( X0 I* ~' w' `1 ^' C6 u' B/ i } 4 e* @1 V+ Y2 S$ r if(Parent.IsEmpty())return false; // 目录名称错误 C6 L1 r; p. h- h( F bool Ret=true; 2 J$ p$ x9 z& p* B0 X. \ if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录6 h0 c# h/ R! N& b1 G0 ?' z Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在# T- J! O3 k' R6 h4 x S& d if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录" m$ A0 w. R4 k% J if(Ret) // 父目录存在,直接创建目录3 K* U5 u% M2 i% o+ V' Y {( ?6 ~5 A6 z; g2 H7 R: X; W6 F SECURITY_ATTRIBUTES sa; ) n5 W# v4 {0 ] J$ ?! L' ? sa.nLength=sizeof(SECURITY_ATTRIBUTES); q7 v$ M! d3 K2 b/ M" z sa.lpSecurityDescriptor=NULL;2 X s6 ~% m5 ^' F: I sa.bInheritHandle=0;& ]9 B# a; ?* h! A# k Ret=CreateDirectory(Path,&sa); 0 e0 _: z/ M2 L5 i% H0 V# t8 i } $ |& G- g* Y4 ?, y; J# m7 s return Ret; % i) d7 N( @" \7 |! K} n; B8 x% j$ j2 O4 c, m! n6 Y 可以看出基本方法是: 4 G' B9 T( R" q" q2 U: I先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; # j' x5 k; j( j/ B如果父目录存在,则直接创建目录,否则自我调用创建父目录。

0 A! ]8 o1 E7 C6 z$ g8 N

/ X3 x! L3 P) m 四、直接删除整个目录:

0 b1 O" O; F# B5 i4 G9 r8 [

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

3 ]- M' [7 q2 d

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 1 [( p% {: N! q+ x1 U' H9 X, ? 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 , f& Q) a/ q# |6 B- }$ l; E如果找到目录,则进行自我调用,即开始递归过程。 9 h3 F! n+ K9 T$ f) f2 V如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 + j0 |% z, j3 U/ ~6 h, U" F- j# Y+ ?具体程序代码如下:

$ i% _6 _* Z, ?& Z" N! w. `

bool DeleteDirectoryEx(const AnsiString &) 8 }5 Q& \6 c# u; L; ]! D{: S- y5 q2 q* q) Q* M3 K* s if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白- a& @# q6 N7 T8 s( ^- @ int len=P.Length(); + x$ \2 S+ E% ?! R: D char *Path=P.c_str(); 5 a+ j: @$ O. Q$ h" }+ { AnsiString Dir=Path;4 ?/ U! n$ F* e2 _ if(Path[len-1]!='\\')Dir=Dir+'\\'; 9 T4 {# I* B$ Q9 S; b AnsiString Files=Dir+"*.*";& }& S& |9 {- C; @6 I WIN32_FIND_DATA wfd; 8 K. W. O8 ]# w HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);6 ]( F8 p( ~+ F- H* f8 h1 L0 p7 Y bool Ret=true; $ Q) |, J, ?% ? AnsiString Tmp; ) s& S) R$ K& K9 p, _" B; N if(hFind!=INVALID_HANDLE_VALUE) : A$ C2 l& n1 @, Y4 z/ ~! r3 \: m {9 }/ h$ Z8 F3 {5 y& K bool bFind=true; + b0 w8 l0 V8 r) |9 ?; Y! ] while(bFind) $ i# _/ E8 t! H7 C6 x* t, T8 ]- h { 3 x9 F+ Q1 D5 W* [6 x) p* W if(wfd.cFileName[0]!='.') // . .. / p: n* P( ~9 |4 V1 {6 O, `& z {6 v2 Z( f9 n/ [, L& M( L% ` Tmp=Dir+wfd.cFileName; $ ]$ i2 N" x! }0 {) o if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)! `. d) S8 _% N" _ { // 删除所有子目录9 ]5 V6 i/ ]$ u2 v Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); 0 C" y1 Q0 l1 h }else2 j" g) C5 V& \* W9 z, y) q { // 删除所有文件 + R1 X5 T, r/ X" ?6 T8 n SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); 4 t# [ |- Q, x3 x( \" ~ Ret=Ret&&DeleteFile(Tmp.c_str()); 7 K, o* H4 T v2 t } " X% d# k. p: j0 w, P+ h/ u } 7 e8 O& G1 K5 @) x& B' P9 Y2 ^1 y bFind=FindNextFile(hFind,&wfd);) ?' y& G9 ~& r6 G# b }- c9 T( L, r* A. D FindClose(hFind);) d V+ y# ^" }* r9 W' G% p } # `7 m: J8 ]* n- u t7 s' \- z# k if(Ret)return RemoveDirectory(Path);- G9 Z7 s @; C# X return false; " I! j$ \$ O; o, L' S( h2 L} 5 [' D) L0 q, n6 l' f$ }2 w4 i( u

9 V9 y! B' j; l

; p. @" B# @5 }* [7 ^, h! _) q

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-9-19 07:28 , Processed in 0.921698 second(s), 53 queries .

回顶部