QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

0 O8 Q7 @: y3 o+ F7 E! L& [& p

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

' h* p4 ~# D. \/ j0 \/ }; K

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

8 M$ y. l4 i! C! D1 d" h) ~

一、判断目录是否存在:

2 C8 w/ Z. X, N8 `1 q9 ?, D0 }" [* c

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

; t5 X2 z: S9 V2 r' C* r5 }; v, L

设char *Dir为带判断的目录2 L- X# I) {* h/ R- s$ C bool Exist; // 最后结果,表示目录是否存在/ V* D$ _2 c0 B if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”* O' {5 C1 x. I7 p4 Y+ Z WIN32_FIND_DATA wfd; // 查找' d* E* N" K3 C3 {; x8 }% {# v HANDLE hFind=FindFirstFile(Dir,&wfd); R% x0 \$ I" N8 L# T. L8 yif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 3 U/ n8 ^! x8 ^; v6 telse' @1 @+ N! q! U- ] { - j' V" y0 u. S8 H6 M- E if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 Z9 \ l4 A/ K& I6 }% | Exist=true; // 是目录,目录存在 ! Y5 f/ U0 s8 C; R( ~ else ( J E" A: Z; k; Z- y* w Exist=false; // 是目录,目录不存在/ m) F% |1 H& k3 G- K6 r6 T5 M FindClose(hFind); : q. g1 H F) w1 D/ Q; N}

- r4 V) m: |0 L- |+ u

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

( ]( o0 u" D- o9 l

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

, I5 I% u p/ z# N: y

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle ' c& Y; B7 `; q- l6 y7 z6 M LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL + h+ s# Q) M" l- N, o! t! gLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 7 |5 B9 _4 h( M1 U* D( N, G LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 # Z- T1 _& L, h) |7 n UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS ! U% S% w* g, T, ~+ d BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL / ]2 U0 A' D! s% z LPARAM lParam; // 预定义的对话框传递给回调函数的值 1 a4 a5 N B: O4 G4 @int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 - Q( ?6 {8 Q3 t, w' V- N0 R- ^2 P X 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 5 @! \( m! _/ x& b _#include <shlobj.h> // 必须包含的头文件! p5 a( p0 T6 L3 s7 { char SelectedDir[MAX_PATH]; // 最终结果 0 ]/ E" L D) fBROWSEINFO bi; // 入参' C6 N- A V& G- \! J+ `, x char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font + u* M% U8 p4 Q* [ RLPITEMIDLIST ItemID; // 所选目录的系统标志指针

$ D# b. h! A. z/ Y8 f9 v

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果! t5 J- g! m% Y7 _5 ]4 G memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据( N1 D% k) B' t bi.hwndOwner = Application->Handle; ( \4 ^( |' ]: N, n* r6 x3 gbi.pszDisplayName = FolderName;. E8 h1 J" ?& _ bi.lpszTitle = "请选择目录"; // 改成自己希望的 % `* i2 }0 p! ]bi.ulFlags=BIF_RETURNONLYFSDIRS; h9 h8 p1 o, eItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框$ C9 M; J+ j7 q7 F if(ItemID)% p0 Z( H& b# L { 4 n6 B* i3 t- N% r3 ?$ S3 z! Y SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 5 g5 a: K. e0 R$ R8 Z GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 - ?( J1 f. [9 v! J, ?! H}

9 H1 a' W! N$ ^1 Z# H& }

三、直接建立多级目录:

! B! y f8 L/ ^" |3 G

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

% A# W# y. f. m, D

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"2 m/ a4 ~ D M( ~/ @7 C { ! Z' C% X2 B% h if(P.IsEmpty())return false;7 F/ w: ^1 v. q& b4 O8 T6 m' w int len=P.Length();+ `* n( @% Z, X5 V% e char *Path=P.c_str();) t2 ^' e) o# F8 z" w if(Path[len-1]=='\\'), D9 G6 T! T6 T { 4 r8 a0 n7 R1 k len--; & l$ N- f$ n0 I F Path[len]='\0'; + B5 M: k+ B' s' j v. Y5 B8 w7 w5 e } // 删除末尾的"\" * u8 C) u$ u; q! J# Z6 n AnsiString Dir=Path; * L5 b$ j3 _: u( N; J // 分开父目录和本身目录名称 % d3 p. T" R$ t5 U. a AnsiString Parent; G& L3 e, F" R [! }- K' a8 D& D for(int i=len-1;i>0;i--) ! |7 A1 p7 ~5 |& b" w {3 h1 e& p4 i1 Y0 \8 Q if(Dir.IsPathDelimiter(i)) Q: d& K. w% ^- {. g! h+ H { $ C0 f! y' Q! U' q* c- f* B( I3 A4 \ Parent=Dir.SubString(0,i);5 W7 h/ r% u/ b3 Z @ break; + x+ i' F( X- O0 z, D } 4 W( l. S3 U& d# C: L& \7 W' h8 r } $ g* G: B' m# P8 @5 Q if(Parent.IsEmpty())return false; // 目录名称错误 2 H: ^9 b, ?9 X6 T bool Ret=true; * g( H! X6 Z2 ?6 o# _ if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录+ n/ t7 z/ y- a3 k+ m Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 2 T( K6 X5 e) ? if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录& v4 V7 }* W% c a n! P: C if(Ret) // 父目录存在,直接创建目录 ' r: K8 E5 E% n0 Q {7 b, ?$ _: ^3 _/ U7 X3 z SECURITY_ATTRIBUTES sa;" G; I1 ~' `% ^7 s4 f sa.nLength=sizeof(SECURITY_ATTRIBUTES);4 i+ p7 ~/ n' p sa.lpSecurityDescriptor=NULL; 6 a/ n) r* ?7 U) K sa.bInheritHandle=0;) s+ W# k8 x1 I) |2 ]' g Ret=CreateDirectory(Path,&sa); + n6 J U8 ?& A& l9 V& r; n } % O* u% E- \8 W( x& ?3 u2 M return Ret; ' ]& y# ?2 x0 n% p1 G} * l+ i, k. w- o. E/ }+ ~1 N 可以看出基本方法是:. v9 D# E4 V, I0 V' { 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; ; i! ^) {" @) W7 ~如果父目录存在,则直接创建目录,否则自我调用创建父目录。

; {1 A/ g3 l0 O6 q8 W' H

9 v# K; k, F& B4 l' q! A 四、直接删除整个目录:

: Z2 c g/ Q5 v- M _0 g

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

" T; Q+ l0 Q5 {4 l7 W

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) . s6 I9 N( Z( D% |, q如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 3 P1 `2 g2 D, f0 o! e; s 如果找到目录,则进行自我调用,即开始递归过程。 . O- p9 j9 @( M1 t0 u0 Q如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 ; D% Z3 S9 R1 o( o5 h 具体程序代码如下:

0 ~) v* |: t, g; g# a3 y' ]1 i

bool DeleteDirectoryEx(const AnsiString &)6 @6 L5 b, q' |5 ^* U+ C {4 O+ ~4 h, X- A% i5 D: \ if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 & M% g7 w. F9 u4 D3 S, G int len=P.Length();0 b6 T2 T: a$ P/ K char *Path=P.c_str(); ( ]' Z+ u1 u" W5 h8 c# t. g7 c4 x AnsiString Dir=Path; # ?- f2 f' [( ^1 o2 \% K if(Path[len-1]!='\\')Dir=Dir+'\\'; , @# N/ A& i9 L* H2 d AnsiString Files=Dir+"*.*";7 K! H* }( v3 f2 x2 q5 ` WIN32_FIND_DATA wfd;8 @3 e- v. U; @0 \; |: R+ O, l HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 5 d W3 z4 p* o bool Ret=true;: x O4 x; @. | AnsiString Tmp;5 h1 G9 N: [1 m: y: v if(hFind!=INVALID_HANDLE_VALUE) ( Y6 H, Y, B, i6 X7 i { $ ~) m. l4 _3 {# m' k( `. C K bool bFind=true;0 B7 m1 X: ]; X( C* z5 s while(bFind)1 l1 w6 b1 r8 n3 v7 T( u { & f' ^" L) ? a! B! H0 r if(wfd.cFileName[0]!='.') // . ..6 h4 K: s" c5 ]/ e; B {; ^+ _! `8 J/ u' R Tmp=Dir+wfd.cFileName; + C9 H- R& @6 y2 \) E1 F if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 5 ]8 f6 i# b2 \! J: \/ p9 P: ~ { // 删除所有子目录& `( n9 H6 I# M; L8 r Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); : h) u& U7 S, t* Y }else/ b) Y: b1 F! F8 n( ~* _5 I { // 删除所有文件9 ?: E' F+ {7 v, B! f m' T0 @ SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);, O" ]. ? r& ~2 J; C& C Ret=Ret&&DeleteFile(Tmp.c_str());$ K9 Z6 M" C7 B: B1 V! i }& N0 ]0 S0 I5 k% _ }( F8 @; C" e, V" T3 [ bFind=FindNextFile(hFind,&wfd);, f3 `9 Z, k* q' u; p$ q2 g% y }0 Z8 A) }* {0 @( ~ FindClose(hFind);- i S6 }3 ?* l% T$ ?; y5 | } . r+ v- U9 i1 U. T if(Ret)return RemoveDirectory(Path); 2 e/ v- a8 O) I0 t& b/ H) M; A3 ~& T return false;/ Z/ O* C% B3 Q1 h' m; A } Z0 ^* H) A! E" r5 }3 d

! ?3 {8 `# m/ P, E4 t2 n& ~( |+ g' _

. c; |4 F. |$ c5 M" I; r" X( X

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-6-10 23:09 , Processed in 0.397507 second(s), 51 queries .

回顶部