QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

0 z9 H9 R" y& ^0 G; M% g

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

% F( z1 {* I b- i% o

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

. o+ H% V9 d9 [/ j9 V( o

一、判断目录是否存在:

* _+ o! c- a9 ]* E) \

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

1 A3 E {, {" M% a( u: H8 ]2 [

设char *Dir为带判断的目录' m, ?0 `8 r2 s* N+ j o bool Exist; // 最后结果,表示目录是否存在( n3 u5 [/ a, ]+ T9 z7 A) i0 R if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”1 X1 {' ]9 { O1 f; | WIN32_FIND_DATA wfd; // 查找% D( O, ^& l5 u, x" ~( @ HANDLE hFind=FindFirstFile(Dir,&wfd); 1 c+ ^, y9 P9 M$ O4 u if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在! @6 r8 p! X: m3 t+ v else * z( o* s8 X. l7 E) A{- i4 D/ k6 c0 a5 F. \+ A ?" H if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 ) ^" C# u$ ^- K3 G1 I Exist=true; // 是目录,目录存在 / T6 u x. g1 t! s9 F else5 S+ p+ q0 V% s; E' w( m# e Exist=false; // 是目录,目录不存在/ V* o6 ]% {8 }2 @# f. @: ` FindClose(hFind); 9 X2 X# X- j) l6 m$ L, e1 c. X2 n}

p% T2 g3 Z2 T) S$ |, { d. F; i

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

. i- D' ~& ^# A' Q5 q8 v; @2 ^$ \

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

1 q {/ \0 M1 c; |0 K( d) V g

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 6 t7 _% x+ I/ [- n( s: G6 fLPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL ' I7 Q6 B4 B$ M. ~LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 * K9 P' _: a I. R5 F/ I LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 1 s& E- a. {4 P* D/ ]- NUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS : J5 j6 Q0 g" G$ V BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL _2 d) @ k& h, K( ?* F: \# Y; x LPARAM lParam; // 预定义的对话框传递给回调函数的值( S& m4 F0 m4 s5 i4 B& v" N p8 ? int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 : ]9 d( N6 H" G5 x) l6 p$ M/ K可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: - A9 S+ z' n0 t: M* ~. I% ^# v#include <shlobj.h> // 必须包含的头文件 ; A$ C ^4 Y$ [4 Z! v& kchar SelectedDir[MAX_PATH]; // 最终结果2 K7 u9 c8 F/ {( {, R& j$ \ BROWSEINFO bi; // 入参' o9 G) Y: _, O7 e3 h v T% m char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font : c' C/ W- c- @# r [5 `6 O4 U8 ` LPITEMIDLIST ItemID; // 所选目录的系统标志指针

" C: z+ q. \, K* g

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果4 H( W2 f% O. F$ l% i! O memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 R# B9 t+ x4 i7 K/ k3 {# V) Jbi.hwndOwner = Application->Handle; # j( e; A: l$ z8 g1 f3 x1 `; y) Cbi.pszDisplayName = FolderName;( r: O* J3 p; \6 X bi.lpszTitle = "请选择目录"; // 改成自己希望的 , n. r0 F1 d3 ?1 s6 c1 h2 ?% ybi.ulFlags=BIF_RETURNONLYFSDIRS;) |# H7 L/ t. h3 ~4 d: X1 f/ r ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 7 r4 @ o9 [" m1 ?if(ItemID)& r! e Q) B2 W6 ~6 Y4 q- A' s { 8 x+ r( L, b1 v) O SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名$ s, {+ C/ b9 U1 @ Q GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放! ?; ]5 g) V4 r* C. w }

( U3 P6 P: n" o' H7 ]7 x# Z

三、直接建立多级目录:

s" R* f: A+ D1 U

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

, ?0 Z7 _: M& a) o

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" W/ g1 ^# ?6 f6 e {5 I& o4 m1 K& H if(P.IsEmpty())return false; * o+ S3 X4 X0 \" L- j1 u% b int len=P.Length(); * K, O' _2 d0 G char *Path=P.c_str(); : d/ E6 n3 I5 S4 B* ~; T# S- O if(Path[len-1]=='\\')0 }9 z7 O& ?4 \( u" w; } { 3 R, N0 Y( ^3 n: k( y D len--; - K& M+ j- R) U Path[len]='\0';9 c3 m5 X4 I3 n8 M* Z } // 删除末尾的"\" + e" R( i7 L2 p- [1 q% h! w. y AnsiString Dir=Path; % c' a3 z+ o( V- {* M# V( b // 分开父目录和本身目录名称2 u- K! u* Q5 |7 p$ f AnsiString Parent; ' ]1 O9 N3 X; y2 e5 h) W for(int i=len-1;i>0;i--)( Q# V+ E/ x' j/ J$ | { ( p# h, k# I1 n6 D% M4 L if(Dir.IsPathDelimiter(i)). f' G! s7 _4 B0 d) O' q5 i' N {4 m+ E3 c7 F& u% q$ s/ @- @9 s Parent=Dir.SubString(0,i); , f/ D' ^. L Z, p break; 2 J8 Q( \" S* A. B) v% n; M, o }0 a2 y% F- }0 f8 F* J } ( H) }+ R+ R. K if(Parent.IsEmpty())return false; // 目录名称错误, ~* Z6 x) H9 h- n+ N" `8 D bool Ret=true; 1 Z! c1 d1 w6 x if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录3 V9 c, }, ^- t0 ` Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 3 e0 A, i7 {2 l if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录! \2 F0 i( s; f i, O t9 t if(Ret) // 父目录存在,直接创建目录) g: k' S! Y7 N { $ q, r5 L/ k* o SECURITY_ATTRIBUTES sa;7 p6 N2 A* {8 B( f5 t$ z sa.nLength=sizeof(SECURITY_ATTRIBUTES); 8 H0 Y4 @3 ]3 M5 M/ k6 a$ @7 S sa.lpSecurityDescriptor=NULL; T) J* t' I: R* d sa.bInheritHandle=0; . F4 N: T. U! E5 ] Ret=CreateDirectory(Path,&sa);( k7 U- _0 t+ |- b J }" V& U! M! X& H/ m7 `- m4 k return Ret;( B( K1 q* _% G1 [. F* p, E) M6 t } . }1 u% t y! I: _$ A5 v) f" j 可以看出基本方法是: ! J. ^) }; i3 X* Y# a先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; # O& m% K6 T% _如果父目录存在,则直接创建目录,否则自我调用创建父目录。

2 c5 ?/ P# u5 U1 A

$ ]5 V: Y0 }( O四、直接删除整个目录:

+ q3 d4 f* M8 s( B

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

7 ^# E. x# W. a3 D0 J+ `

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) / U4 _2 \1 n- h: G! ^2 D 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 ) |5 O3 y2 E Y2 d 如果找到目录,则进行自我调用,即开始递归过程。 & k7 r. C7 z) O3 ] 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 5 l ^# z6 `; u' o* W具体程序代码如下:

( Q m- |: Y$ ~. f

bool DeleteDirectoryEx(const AnsiString &)# l9 }5 s/ G' m' {) S {4 J% N! i4 Z" P' _9 i if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白/ T) g6 j3 q) T2 ~( [0 P t/ m int len=P.Length();7 K8 f+ X/ b/ v8 |; v char *Path=P.c_str(); ) U- \0 @6 Q: ~$ O' V9 H! ?& i$ ] AnsiString Dir=Path; 1 a9 z2 Z: \ b2 n if(Path[len-1]!='\\')Dir=Dir+'\\'; 9 Q1 S, h. u* U9 E) k$ m# X( k6 N$ _ AnsiString Files=Dir+"*.*"; . j- D A* i5 L2 i5 u WIN32_FIND_DATA wfd; # T! X/ W# Q$ X# s( U. j) u HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); : n5 y( p- Q8 C2 w bool Ret=true; 7 p5 U: A( z! f2 a3 ~$ F' p; d: X AnsiString Tmp;* O! s* l* y' K8 J$ \ if(hFind!=INVALID_HANDLE_VALUE) * f. x6 N& g, p# d3 C/ y: Y {* M8 l* [4 I) l bool bFind=true; 2 a& U2 u8 w" l while(bFind) [+ i& u) g, @6 {; i% i2 s$ U' p {( j0 k# g7 x, s, \ if(wfd.cFileName[0]!='.') // . ..; }& l/ h @4 H2 e2 K) M {4 H4 g% M2 i. \" k9 l Tmp=Dir+wfd.cFileName;. n6 |& U/ U7 I! I7 j8 v( X if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)! S; k* s+ `; R) R! M/ ~! D { // 删除所有子目录 ' w' E3 Q0 Q: f+ } Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); + J& G. I/ ~8 l9 Z1 r% L0 Q; z }else" S! I: ?) d9 e' I$ |# `, d { // 删除所有文件% `0 A/ l4 G1 C1 j5 I$ S: j SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);/ P f/ J# Q$ _! O Ret=Ret&&DeleteFile(Tmp.c_str()); 1 `( \/ T# g f1 n; ]1 S }# y6 Z* X, b. B5 m' c }4 J8 m& B8 q! K* U3 _" ^ bFind=FindNextFile(hFind,&wfd); . B K F5 H8 v! n1 S2 T N, F0 N/ X } 7 ~% i$ _( c: s \2 K, P8 j7 z FindClose(hFind); ; L! X: X0 l+ b: y, J } 6 {8 X) A* t+ W: Z D8 I if(Ret)return RemoveDirectory(Path);* x' K5 ^& I* N1 ?- `. ]4 Y return false;; E0 e' i- t' T% _4 R; x! K, t; _ } : j* C N2 \: b6 j% ] i, x完

6 X: Y D8 ^; [, r! b1 ]) {

2 h& `- w1 L, o" H" i0 }

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-10-14 03:50 , Processed in 1.710443 second(s), 52 queries .

回顶部