QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

$ |/ ~* Q! |+ C4 l, g

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

% o5 z( m2 X. Z2 ?; _

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

7 R4 r! J+ y4 W( [

一、判断目录是否存在:

- ?; ?% @& `2 N

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

# N+ k+ ~, u. j

设char *Dir为带判断的目录 " R5 @4 n# y. ]bool Exist; // 最后结果,表示目录是否存在 M- M- T* r5 t# z) l. \1 t, e& \if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”* }$ ]6 f' H- D( C+ g+ M( X WIN32_FIND_DATA wfd; // 查找- o4 S3 ~3 G% c8 I HANDLE hFind=FindFirstFile(Dir,&wfd); 2 d* d# E/ W1 m4 f0 U- `& oif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在. U; ^; F2 `) L0 q0 ^+ o+ J else 7 F6 G H/ A. H) Q3 D5 z9 `{ ( x X, C; [' P2 I. l if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 % n+ Y; D/ k. R0 ~0 r: o3 W Exist=true; // 是目录,目录存在 + k! G. f2 j0 P9 Q/ N' _: r# y else , K1 j" W" e$ n/ v {* n% o Exist=false; // 是目录,目录不存在) X( P) t0 V/ A, _: s9 B& m FindClose(hFind); 3 W1 g6 d& J2 A7 k5 p}

! T8 w8 N* I$ R% u( H

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

8 E- G% I, @/ J: ^4 Z, J

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

1 I8 C w4 C* j: z% d7 w

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle * F, J/ f0 V7 qLPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL) @( F" {1 ^% C! k, Z0 o! \ LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 6 `, [! p7 K. ]* _# tLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 % ^4 B7 }4 G2 |) o& I) m/ @ UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 1 {& w4 f4 b: k BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 5 J/ L3 C* S3 y. ]0 n' n7 Y LPARAM lParam; // 预定义的对话框传递给回调函数的值) |0 Z0 Q5 ^3 M2 ^ N int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 9 ]0 J. M$ q ~ B) e# C9 x3 T 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: . T0 Z. T4 I- Z% Z7 {#include <shlobj.h> // 必须包含的头文件) B1 ~8 k3 L' b$ D, G& ?3 C M char SelectedDir[MAX_PATH]; // 最终结果+ _( r. \+ S. G( a& p8 V BROWSEINFO bi; // 入参4 q4 t- U) f8 K! S g: _ char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font . B5 x6 h$ o$ l3 MLPITEMIDLIST ItemID; // 所选目录的系统标志指针

) N! ^- Q9 e6 S" ]* X

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果( F1 F' g$ [* Z9 o" w: e8 d memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 ! o$ ^6 ]% u% N4 B+ q8 @# bbi.hwndOwner = Application->Handle; & e6 K1 X& l9 K0 o, f+ H' mbi.pszDisplayName = FolderName; 1 P0 O$ q$ c0 A9 ]1 T' k% lbi.lpszTitle = "请选择目录"; // 改成自己希望的/ V: i- c. l. g+ A. w5 R bi.ulFlags=BIF_RETURNONLYFSDIRS;1 s6 N7 g& R' T- O+ |) Q( n ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框0 }" @% G- V. V3 ^; n+ {7 U if(ItemID)% c0 R' v* s3 W& m { ! {. ?0 R* J) B4 H SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 X4 `& W9 @; m GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 4 G% S2 m+ \+ v. o. o/ w7 N0 H}

9 g4 t8 W# p6 ~! N2 f% q

三、直接建立多级目录:

- C# a$ d6 @( Q8 N: G3 ^9 \

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

X$ b v& W- _! h; y+ Y+ z

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" & @% T& l1 M% s3 C{4 e$ t0 H7 C9 J% X if(P.IsEmpty())return false; . `, s: o; y$ x7 z int len=P.Length(); 5 {1 B/ s* L7 P+ @) j# k# {0 u3 \ char *Path=P.c_str(); - F0 Y- l/ [' G1 v2 I4 V if(Path[len-1]=='\\') 3 J; O/ e5 o, d/ }* m9 B- |2 y7 m0 \ { ' P7 i* z1 [+ U/ F9 h2 M len--; 0 _2 q, i7 \% `$ V9 i Path[len]='\0';$ b4 y1 ?5 _+ d: H1 [. b; K } // 删除末尾的"\" / T" j& f2 W$ [9 _- ?9 `: P* u0 J AnsiString Dir=Path; & [! Z2 J0 t. h6 G+ s0 P) g7 l // 分开父目录和本身目录名称/ J9 ^' K8 y) j( ] AnsiString Parent;0 @6 |$ J: L% J* i! P& A B for(int i=len-1;i>0;i--) + @6 P5 @& a' d5 d: r7 d { 9 O& \: a- [3 z if(Dir.IsPathDelimiter(i)) 6 K, A1 v% p( m { . R# d3 H* x# q+ \8 B Parent=Dir.SubString(0,i);& m/ b8 Y3 F0 ~# {3 E: v break;9 _& W$ V. l4 n7 V- a3 ?( X } 2 G; }$ O# u4 L, j$ Z3 b2 m } 4 C, H K/ O7 L$ |1 ~- I+ k if(Parent.IsEmpty())return false; // 目录名称错误 2 P& @7 x! n6 |& e; u bool Ret=true;* X6 M( v. |1 E" z* t+ R- q; R if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 , r) A. q0 f( v0 [" t% G1 V/ \ Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 # \3 Y: w% C1 S! u# o if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 " d9 D, }1 a( @ if(Ret) // 父目录存在,直接创建目录) y/ R6 U* s2 A9 G { 1 [# n/ g+ b/ N( J1 n; A8 ` SECURITY_ATTRIBUTES sa;7 y5 F4 X' X0 G+ C sa.nLength=sizeof(SECURITY_ATTRIBUTES);1 I+ Q+ P1 K, ] sa.lpSecurityDescriptor=NULL;! P8 M1 [3 n& L% K sa.bInheritHandle=0;2 Q& d5 [& t8 h) |- x Ret=CreateDirectory(Path,&sa); ; B4 r# ^! S. Y& |5 c: v } 7 } c/ i# x' p, p. ` return Ret; / s \7 n3 o- o, B# W} ; Z# H# `; Y! r" V3 m 可以看出基本方法是: 4 R2 E% O/ ]$ \先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; $ ^, Y7 T3 P1 t4 M' C 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

0 g* c7 x3 c$ W# L

' G6 w, E" n. z' J$ A 四、直接删除整个目录:

6 A5 @8 A+ T, l+ b: ~ G

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

0 x0 p; ^9 k+ b" Q

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) ' B/ ?+ N8 J! D3 R2 [5 |' i4 h; B 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 s0 y7 E9 M6 j5 h ?) l! o如果找到目录,则进行自我调用,即开始递归过程。 2 {" k/ h$ ~! [7 p如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 , {* R' J+ X/ ` 具体程序代码如下:

5 f( L2 b5 Q( y4 s5 u, X

bool DeleteDirectoryEx(const AnsiString &) 8 q. E6 {" u$ h) J{ 7 A- R' R! X+ r& U* R& f if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 1 }$ J% P8 p! x) m8 W int len=P.Length(); 8 g- G( _& X) T2 I0 E char *Path=P.c_str();* w0 A. o( U" k4 [7 d6 k" n3 W AnsiString Dir=Path; ' [' {4 _3 J; ]* I# ?* s if(Path[len-1]!='\\')Dir=Dir+'\\'; " D. v* Y( l* Z2 v AnsiString Files=Dir+"*.*";) c& ?, |8 d9 p o. j WIN32_FIND_DATA wfd;* e1 @; @+ J& N' E" g' x HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); ! C; b" A0 B+ a2 F; P bool Ret=true; . w/ g4 p$ E7 i# z AnsiString Tmp; 9 _+ B( `8 Q8 P3 I if(hFind!=INVALID_HANDLE_VALUE)& x. E o6 P9 `$ @ v { ' p' Z; n1 q, b/ V# t1 G bool bFind=true; ) k/ w- Z0 Q5 F/ x2 S( V3 y while(bFind)5 L/ B7 p" N+ D& _5 d: t5 j {- q* W( A- x6 a9 t4 k& D if(wfd.cFileName[0]!='.') // . ..% k( ~) s5 O' g8 }# ^. n% ?" T, {2 o { 7 ]3 S) V X/ O% v Tmp=Dir+wfd.cFileName; 0 ?. H3 s" B- D1 ? if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)' d+ |6 i3 |+ S' e { // 删除所有子目录 / {$ B3 i4 A% F1 }. b/ F Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); , S6 i+ Y. l5 n }else& h! L6 |) z/ ~" r2 Q+ ^ { // 删除所有文件 % B2 a3 G4 g4 b- T0 f' a SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);3 U6 K) b9 _0 z& A% F0 D* x! R Ret=Ret&&DeleteFile(Tmp.c_str()); ! ]8 k6 K. ^; z9 o4 X/ r1 x- F } " H) a; ? O7 F9 j2 a- ]1 C } $ c8 n9 I4 v1 m& g( i$ Q! n' E bFind=FindNextFile(hFind,&wfd);' z* J' H0 f& {# i } - r) Y0 N) U" M/ V, |! \ FindClose(hFind); ; b( i% I: R2 P( g4 y, s } ( U! j& l" n% v. n7 j if(Ret)return RemoveDirectory(Path); . F$ N- D$ R& M9 ` return false;7 J7 |8 s! @$ I9 L3 w3 ?" u } $ \/ Z" X. S3 t e7 D# a: I

W' J v: S+ p$ E @) t/ Q

- x) l o, G1 ^0 {

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-17 22:47 , Processed in 0.683184 second(s), 52 queries .

回顶部