QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

2 O Q! o+ t- ^8 T( b3 e* ^& o

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

% H' L9 y: B; F$ a$ q8 j7 G! N

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

$ y. v# m4 W" I. @; U' J

一、判断目录是否存在:

, }/ I+ D7 E5 Z4 q# ^

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

/ j1 n) w- o" }% b# R0 Y9 O" }

设char *Dir为带判断的目录8 M! D( D) W$ t1 l7 G. S bool Exist; // 最后结果,表示目录是否存在 l# m. [9 v+ |# x( U- s if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” 9 a: p4 b3 q4 h: }" p" U5 k( qWIN32_FIND_DATA wfd; // 查找 , r% \. F& K/ g: O _- AHANDLE hFind=FindFirstFile(Dir,&wfd); 5 W/ f2 K4 H5 x' C0 \5 g if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在2 l Y D" _$ O else. b' u5 I1 y) |7 Z% \ ]: f2 k& q { 4 J |; L' a# h: }4 ` if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 " J+ X H) I2 t9 E! {9 ~6 O Exist=true; // 是目录,目录存在 * Y" J. O, Y/ f& | else 4 K+ k( ?& R+ C9 h# U, g Exist=false; // 是目录,目录不存在 - w, v' W& L3 O. A0 T, b FindClose(hFind);) U# D! E# Z8 c; c* k" w4 r }

8 D; }, L" x& G/ U6 G6 H

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

, U3 f& G1 Z% N% s

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

& C8 u1 [. ?6 ?9 v. {+ N( ~8 Y, l5 c

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle ) Z8 e, b* b: n9 y" r5 CLPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL) Z% m$ a1 c( w LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 - F& b, u; b. n; X7 @ LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 - s/ K# n1 @: @1 u/ A UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS ' D2 r% p2 ?9 [- b/ g; X$ W: Y; kBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 8 |0 M8 Q1 ^/ J6 Y) l9 B+ `) S- J+ [% rLPARAM lParam; // 预定义的对话框传递给回调函数的值 . Y; f2 u8 t" ]int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 3 l! ]0 @8 e- F D, `/ y- D, y$ C8 N可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: S8 X& O" E1 O #include <shlobj.h> // 必须包含的头文件 % n2 @. R" X7 z: x. Echar SelectedDir[MAX_PATH]; // 最终结果9 L( u" K1 W4 O6 o3 ` BROWSEINFO bi; // 入参 n8 a, C0 |8 f4 Y# f5 schar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font * A1 Z; t; w9 jLPITEMIDLIST ItemID; // 所选目录的系统标志指针

3 c9 I+ a$ e- X( H. h

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果2 O1 R6 v! k; |6 f, T" \/ b( o memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 8 t' |8 O7 l1 a) N/ Wbi.hwndOwner = Application->Handle; ' [' M6 N1 W2 M7 g- ]2 hbi.pszDisplayName = FolderName;0 x4 [5 k+ \% f2 u bi.lpszTitle = "请选择目录"; // 改成自己希望的5 w9 k! b! R- i; k bi.ulFlags=BIF_RETURNONLYFSDIRS; r# y. V2 p, y6 j. t ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框% |. L& |$ l# s! R% {4 I if(ItemID) 5 W. ?1 e! Y, `$ W' N+ G{ ( ?! t" W, T- M6 d/ m% }0 R4 r1 A SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名, q2 ?% y% R5 E+ R GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放+ v0 L" V( L1 X( z3 F }

% |/ P% w0 S: S: F, J- Y0 ^

三、直接建立多级目录:

2 J" X0 Y: z8 h3 y8 p; R: L2 n' U

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

+ \8 o$ p, s |4 Y9 A0 Z m

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" . I" D! I1 v7 A" E{! `2 x- \* g* b' W- z! Y+ ] if(P.IsEmpty())return false;; T9 B2 S& b, P; F9 b int len=P.Length();: u4 o; A' g6 X% O) l char *Path=P.c_str(); - N+ |+ n' ~/ @7 r+ k0 N if(Path[len-1]=='\\')4 Z( g0 M8 p! `; s5 L& L9 N {6 x4 S$ o, z* [' _2 T/ [, I3 G len--; ' c- Y. e) S8 L8 S Path[len]='\0'; 8 J( |# h* M$ `* g4 C. G& a. E1 }6 ~3 R } // 删除末尾的"\" . t# Q- K5 m2 l( ] AnsiString Dir=Path;2 G6 g; T) ]4 _4 f( i // 分开父目录和本身目录名称 " e- E* \! E4 b1 `5 f AnsiString Parent; + u8 J6 B) o8 p+ c V+ @! n for(int i=len-1;i>0;i--)2 x, S5 c9 w# @6 X { 4 c s9 h |0 x* ]# r! j0 F if(Dir.IsPathDelimiter(i))6 X/ V' W* t E9 h! Z" D- H { 6 N3 R6 V2 x* y. Y' @ Parent=Dir.SubString(0,i); , x' I- J, `! U, L: y break;( E2 Y# z7 h" N5 s } R: v7 E) J1 K4 E" h } 3 ~1 s6 d' ]! W! ]% l( V# t if(Parent.IsEmpty())return false; // 目录名称错误 8 G4 ]( \1 u. R _' v |( s. n$ V bool Ret=true;( w7 `# a# ~( V& k. G0 H/ v: } if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 2 B: e$ R" K- Q" m3 c% L, J4 A Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 - S# j8 h& g2 K y( Z if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录! W- @8 l+ Y7 G- l0 z8 e7 ` if(Ret) // 父目录存在,直接创建目录$ c3 h3 [1 d. i. ` {) ]/ C' I! L4 _2 d* r SECURITY_ATTRIBUTES sa;& d6 r% F; L' a% F sa.nLength=sizeof(SECURITY_ATTRIBUTES); m) X# i( U! \& I sa.lpSecurityDescriptor=NULL;9 y- h3 s8 H" _2 I1 u1 I% y3 p sa.bInheritHandle=0;3 n/ y5 W; w* h$ O6 D8 D0 \ Ret=CreateDirectory(Path,&sa); ! b z+ W2 O( o5 Q; b }- @0 B4 j2 e8 E7 e return Ret; 8 `: ~5 U* Q7 C9 Z} : O, _8 c2 e) g8 G- ^, s! z# y( ?0 h 可以看出基本方法是: ; g4 _3 K3 M2 @, E" i; u8 q先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; . }! K# B! g$ X如果父目录存在,则直接创建目录,否则自我调用创建父目录。

( C$ z' n1 ~' [# T& A

, m6 W4 u7 o- R9 W5 K" s- e5 C0 d+ I四、直接删除整个目录:

( q j6 @/ y$ [& n; Y! _

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

7 L! o/ h# g/ V2 U. Q' r/ |; p

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) . }+ c' B4 T. w& [+ t5 b7 m% ] 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 ) U( A2 g; l2 J 如果找到目录,则进行自我调用,即开始递归过程。 # N# A E" j3 U$ u! U, G( {0 ~ 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 ! S8 Q' n( {9 b+ |; X/ _/ Y具体程序代码如下:

* S! g( k5 A* P6 v/ ^

bool DeleteDirectoryEx(const AnsiString &)/ ?+ T4 @3 }( b7 s( k0 r { $ _6 ]3 E( h# U5 k/ _- d if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 4 W- i" R0 o3 m5 h, S5 Z) q int len=P.Length(); " ^6 a6 r; \4 E( Y' J6 X char *Path=P.c_str(); 8 o; @' W* s3 i8 ?0 ?1 e AnsiString Dir=Path; # R" j7 Q: Y) l, c% z ~ if(Path[len-1]!='\\')Dir=Dir+'\\'; ( d4 L$ n4 J7 H0 N AnsiString Files=Dir+"*.*";0 k* |: y/ p& e WIN32_FIND_DATA wfd;1 q9 {/ L. L9 B5 n HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); # k- z, x- v4 u! Z, ]0 { bool Ret=true;. h3 k5 c& s0 r' D& _! F* o/ D3 w; g AnsiString Tmp;( B$ t% F2 ^* ^0 U1 n' q, K if(hFind!=INVALID_HANDLE_VALUE) # j" S9 p9 K/ ? { 4 R+ b6 T1 k+ g9 H0 C3 ^5 f bool bFind=true; * K( l% i6 x; P1 {# M/ e0 E0 ?( e1 n while(bFind) , ]* ]7 ?# _ a0 Q' n. c {3 e3 ]) J- N, ` if(wfd.cFileName[0]!='.') // . .. 7 V) o0 J( \8 x+ i4 B [ {5 R+ Z; P& {; N3 d$ g& [ Tmp=Dir+wfd.cFileName; 0 F% [8 \0 \" x: F. w+ ` if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 6 ?& N% Z- D3 P) F1 K9 u5 M7 I3 F { // 删除所有子目录* _$ b3 x' |, U9 D& f4 r) D Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);: b _: |4 N/ k! Y }else ( I+ @3 r. z1 [* L/ b { // 删除所有文件 4 T9 q2 Q& B2 o- H0 u7 C8 Y+ T- P SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);) N) p% u7 i+ p8 d4 J$ c; G5 e Ret=Ret&&DeleteFile(Tmp.c_str()); 3 J, r) I+ [- U9 _1 U% W }5 z6 ^; B0 ?/ z$ N }! V, N7 M+ t, g& Y9 s5 O bFind=FindNextFile(hFind,&wfd);! K0 Y% F$ |9 ^ |: h* d }) ~* l8 `1 O' I# H2 B- W D FindClose(hFind);/ ]9 B( U1 R) p4 z. W }; C: @* d9 v8 z if(Ret)return RemoveDirectory(Path);* K/ h+ F4 @# b$ R# g# K* B return false;1 M& Q& l ^% M } 4 _6 s/ u( p9 O1 W' P7 b完

4 U z$ x% u: K8 t

( l- V% Y8 L- }$ ^5 w

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 07:03 , Processed in 0.332648 second(s), 52 queries .

回顶部