QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

# j" L) }" w: i" x

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

3 T2 r& k8 N0 R/ x/ K D

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

0 K$ Q, P1 J) H' P1 J

一、判断目录是否存在:

7 T$ h" Y' |. ]9 H; Q: G

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

: L7 q6 [6 m- Z/ j& A

设char *Dir为带判断的目录 + Q+ q2 V- B, Y% y5 K" Ebool Exist; // 最后结果,表示目录是否存在 1 i; O( O7 C7 t! }if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” ' v5 j+ I4 R. `* ~! uWIN32_FIND_DATA wfd; // 查找 , A! v$ R6 _ k" B% LHANDLE hFind=FindFirstFile(Dir,&wfd); % q# \5 Y6 ~5 J& X if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在; N7 D$ k" K2 E, X+ [( e else* k1 }; ?/ k$ ~/ X+ d {: f/ R- ^$ U! [, I% _; Z) h if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录) J6 X4 j/ g% U; A* ?' c Exist=true; // 是目录,目录存在 # `2 r5 [1 h; I0 p0 d- q else 3 P; p, O+ j8 X8 n& m/ K; v Exist=false; // 是目录,目录不存在4 }+ ~. D. h5 J% R9 K FindClose(hFind); , f& L- e, H. P* t$ G) ^- v}

! Z4 {6 s/ f# x

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

$ d# E$ P$ f+ `0 A6 \5 e( ^9 y

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

. f, i; l6 H7 k0 V$ t

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle % X1 y9 D7 r" y LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL ! h8 b1 k$ I6 TLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 2 S. p7 ?) X( y- s5 oLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 ) D. _, R& b+ e. lUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS e5 V$ i9 S0 k. ^+ yBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL . l0 J; S8 a4 {- VLPARAM lParam; // 预定义的对话框传递给回调函数的值 ' S1 t2 v+ N) V) w2 O3 V/ s1 Dint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 6 C! t2 A# K! }4 \可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 9 V6 b( H6 f( |; h! r#include <shlobj.h> // 必须包含的头文件4 |) B- |9 O# q. V5 w char SelectedDir[MAX_PATH]; // 最终结果 - {. ?* L Z! P1 n5 k' l! dBROWSEINFO bi; // 入参 " v0 u$ F9 {* Echar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font 6 _9 [! N! E3 c* L+ ~7 U- K$ HLPITEMIDLIST ItemID; // 所选目录的系统标志指针

' ~* e! g# _4 y6 ]8 m; _

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 * N% ?, p+ J$ W7 e5 k8 u; _memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据$ Q! a" G0 J2 | bi.hwndOwner = Application->Handle;! k& p# i! H* n bi.pszDisplayName = FolderName;0 B' P D+ N) T7 B bi.lpszTitle = "请选择目录"; // 改成自己希望的 6 }/ F5 o8 P3 H- i) e5 p) lbi.ulFlags=BIF_RETURNONLYFSDIRS; % A1 c" I6 [" d3 I( OItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 ; j$ V4 @0 p! R# t# k8 F5 qif(ItemID) * } a. _' K+ r# d9 [{ 7 A. w; } n, P SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名3 j/ d& @0 X5 @5 i; s" ? GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 # j4 I, Z( d: {}

# l: y& J0 G2 D) y* N

三、直接建立多级目录:

4 W3 ^( b9 [4 g3 v* T2 r) m2 S8 \

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

# K' X" y- ?6 B2 D% u

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" 2 e. q4 R. [8 Y+ j{ $ E# T G# \: f! e! _ if(P.IsEmpty())return false; ; T" D2 y1 E3 [& L int len=P.Length(); % |4 g+ |0 N2 j; k& `1 b char *Path=P.c_str();; y7 N- X' t3 l; e3 N3 m if(Path[len-1]=='\\')# ~4 w. a6 p7 ^0 g/ f5 l2 }! Q { ( t/ M: q3 x$ t1 W/ i0 P7 m len--;6 D7 M7 S2 W* ?. w; i: T6 h Path[len]='\0'; 5 V2 W7 l* j9 q! \% d } // 删除末尾的"\"$ S5 Y: `: G" G3 B; d4 { AnsiString Dir=Path; $ @! l P j2 E* V // 分开父目录和本身目录名称1 s! R A$ g8 W1 f1 X AnsiString Parent; - e h9 U3 b9 S! S8 e0 C! ? for(int i=len-1;i>0;i--) 4 d- F8 g- ]& Y7 h5 F- |6 W/ V, \ {7 r' E |2 n3 b* C2 T% p% d: O if(Dir.IsPathDelimiter(i)) ' x- [* [' \1 E) D5 P {2 W7 y+ d: M- I( b Parent=Dir.SubString(0,i); {/ H- x) x& }/ L: l" B6 F break;" ~ o+ ]' V. Y- n9 G } . j: P4 M! G/ K W8 f! {! f }5 k" {: p: G* B0 @0 } if(Parent.IsEmpty())return false; // 目录名称错误. F. a( v" h d- z bool Ret=true; 9 ]& `6 W$ _2 G, z. a/ X. D if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 ' H9 T) `5 X& e3 u' n3 H Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 - m# a1 o. _2 I! L0 n7 {7 _4 r( ` if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录4 P/ Q& u9 k8 ~3 F if(Ret) // 父目录存在,直接创建目录0 r5 A T$ R" O% w& q0 T {9 D$ p8 w1 c) D. C- m+ y SECURITY_ATTRIBUTES sa; ) ~; P M$ | O s8 @* O9 s; A sa.nLength=sizeof(SECURITY_ATTRIBUTES); $ ]. j% u; Z9 \2 |/ e! I sa.lpSecurityDescriptor=NULL; 5 k8 ~$ O4 c8 t( @* l sa.bInheritHandle=0;8 {2 t8 t& E' Z Ret=CreateDirectory(Path,&sa); - k& d/ _3 A) m6 Z" y; P+ a, c: u( \ } 3 X) d- Y9 B' L9 A- s' \! P return Ret; : s; O9 I$ r. P. W4 j2 t T0 M/ J} 3 O" j/ Q$ Q% p, `7 j. X- d 可以看出基本方法是: 5 ]: Z% T% I [; q6 O. ]. W先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; . d1 T/ x% c5 }( ? 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

F* V/ X# q+ x* R

% L. L6 G# L- ]( w8 ~% R四、直接删除整个目录:

. n- ], @# ~( X% y& s- B& D' d, B

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

* X) v I( A% X; _3 X( w

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) - l- A& L! }# {" T! A如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 5 ]. C/ m; A* n" |! f1 u 如果找到目录,则进行自我调用,即开始递归过程。 ( h0 ~, M7 a7 Z: q# w如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 2 a+ m t8 J3 \% j$ _具体程序代码如下:

% o* U9 v3 X: `

bool DeleteDirectoryEx(const AnsiString &) + _: k( ^4 D! C{ K+ N0 }6 C5 ~/ [ [% p9 ~ if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白6 p6 C' I1 b& O( |7 r5 ]+ L int len=P.Length(); 6 L1 i% w( U5 {( U, D) Q char *Path=P.c_str();( _3 @: b5 N* s( N" ^; z: k AnsiString Dir=Path;& O7 q- ^4 z, U0 ]! B) h if(Path[len-1]!='\\')Dir=Dir+'\\'; : |; i% K, X4 y+ [; _* @: { AnsiString Files=Dir+"*.*";1 t R5 @' b. |/ p WIN32_FIND_DATA wfd;, Y0 q! p; n% f; S0 Z5 x( x% \ HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);4 Z# J; L: b, v) X' a' V) |( ? bool Ret=true;: w3 a5 B0 @ n/ G C( N AnsiString Tmp; % a3 o. j' I6 ?9 ` if(hFind!=INVALID_HANDLE_VALUE)+ r9 R' c2 M+ D& K: z' r4 @ {$ [* j$ e9 f; d9 V' D/ K3 e% p bool bFind=true;- o2 f, @* [' O6 J( I1 C# h while(bFind)1 l% M5 I2 _5 R* e3 N$ [2 k' i {: ? { y* a" L% ?, K if(wfd.cFileName[0]!='.') // . .. 1 S" R- p) E8 U% S: | { A3 L9 ?0 @& |4 D9 M. T( f! D Tmp=Dir+wfd.cFileName; * E( `, J) e. E( C# u. P if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)# }- ]% p+ e/ l { // 删除所有子目录 & @. Y1 ]$ w2 J2 S" ]; G# _ Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); ; m9 h5 q9 l" F% ^- t& P }else % G+ z' W# t5 e3 e5 f7 n { // 删除所有文件 2 j6 \9 O: A5 T4 R& [ SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);% \/ n! Q1 m) w W1 Z: n4 X3 b Ret=Ret&&DeleteFile(Tmp.c_str()); ( ?& c: F# Q5 ]% Z( R6 T } ' q. I8 N8 d& b4 K/ h- _9 K }3 u1 w f' r# w) | bFind=FindNextFile(hFind,&wfd);1 N+ c$ ^+ B. U* l! }$ J9 Y" Y. w } & o- n4 u' x+ Z, ~ FindClose(hFind);0 T. f: y; m8 P; Z+ S$ o3 `8 s$ E }, v( a- j4 Z8 m4 y/ A* i9 L' B if(Ret)return RemoveDirectory(Path);4 T$ }* A' b6 c5 k6 s4 r/ `# Y$ ` return false;! h6 N+ G8 b7 r5 h' [ } 9 q, J1 Y3 [4 }5 Y

# b" m$ W. r3 c- H8 T* C

) a, \# ~3 t; o& v" z" |- {

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-7-16 18:59 , Processed in 0.447096 second(s), 51 queries .

回顶部