QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

+ y& ]. g# F: O) G/ Y" Y

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

+ L5 y7 g. r) o6 m" a. Y

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

- o8 v* _- Y* E5 f

一、判断目录是否存在:

% F) _1 `% o; d# y6 J" V

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

+ |# i; L* k5 T3 C+ W

设char *Dir为带判断的目录 $ b7 ^" o, L+ W5 jbool Exist; // 最后结果,表示目录是否存在, Y6 h: I: t/ ]& X if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” # T8 e+ G4 U7 R8 n5 v8 kWIN32_FIND_DATA wfd; // 查找 ( m4 @9 Z% r: h8 P6 O, L$ VHANDLE hFind=FindFirstFile(Dir,&wfd); + u+ d9 O: U5 ~8 D: L$ R if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在7 W3 H1 p/ R( e; J4 I" M. w else6 @2 H6 d* B6 w! w {3 r4 ~% g, Y8 f; c( G% L$ l if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 ]4 @' t( V4 l/ _5 q$ ?3 N Exist=true; // 是目录,目录存在 % Z2 Q0 T" v& @# j, L8 \- K else * r" W* {) ]8 B2 k# @3 N% n Z3 U! e Exist=false; // 是目录,目录不存在: l$ c4 u4 ` [5 C8 q FindClose(hFind); - Y" S! Q k3 ^; b B5 `7 A' F}

) h6 [* M, _ w- L. W- l; n8 b

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

/ S4 h4 B, E. r

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

5 o) `( _ a# D; M& s+ o8 Q

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle " C# H6 v' t# WLPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL; T6 z1 {: B& w2 B, G4 _ LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 q9 H# w4 Y, _) t y/ _LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 ( W# h5 i+ l4 F4 s. B8 [% VUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS : P1 _) L4 F( k5 s/ Y. ABFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 3 x7 o+ T2 d+ [( a" u% w& D( R- z LPARAM lParam; // 预定义的对话框传递给回调函数的值 4 ~5 j8 |6 I' t ~int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 . Y) g+ R$ u# z- f3 A9 o* n- v 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: ! V1 }0 p4 D2 u$ h4 O, u' [. | Q #include <shlobj.h> // 必须包含的头文件8 I8 F- g D& c# {8 ` char SelectedDir[MAX_PATH]; // 最终结果 3 r- Q, X- c# B, `( W( @BROWSEINFO bi; // 入参 5 q$ ]0 ]) r3 r3 uchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font / L3 k- V. p9 i* _5 U LPITEMIDLIST ItemID; // 所选目录的系统标志指针

! B* A$ w2 {8 A, e

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 % ~ Y7 v& p+ }3 F- l% Wmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 7 d$ z) h& ^8 S0 Z6 b. \bi.hwndOwner = Application->Handle; ' k- i+ z: N& P0 Pbi.pszDisplayName = FolderName; 1 x: n, P+ l w! G+ mbi.lpszTitle = "请选择目录"; // 改成自己希望的 : E7 ^6 d- o2 v# c. M" R- xbi.ulFlags=BIF_RETURNONLYFSDIRS; 7 B/ ^7 Q) s9 XItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 5 F& ]8 I$ w9 e, O, f2 Tif(ItemID): G+ {9 F I5 d { ) T/ p9 D7 Z: h! `4 r SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名, A$ N r# q2 d$ `6 h GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 9 o: V$ K$ u" a, e- g# Y" t}

! l" e" b& D( I

三、直接建立多级目录:

8 H7 L# _# @& ^* u0 l" }" N" u

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

7 B- W, z9 H% q/ u5 d

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"" n& L4 J( f1 c" V# @ {- v) R6 s& t- Q5 a3 i, H& ] if(P.IsEmpty())return false; . b* T3 I9 _8 m& _9 e- A4 w5 _2 p int len=P.Length(); * `+ o3 u' L/ J% d char *Path=P.c_str();4 L: E6 [, U5 a3 Y1 {1 E) \6 ~$ l- _" i if(Path[len-1]=='\\') 5 |& `+ e3 J7 g0 P5 m { " P) Y# j$ Q* a2 M. B len--;) A: v5 V5 G2 u9 H$ q Path[len]='\0';8 D( v+ G/ _4 B- q& E } // 删除末尾的"\"7 o% S, @7 E6 U' X( s1 P AnsiString Dir=Path; & d. p: b: m+ {% u" F // 分开父目录和本身目录名称4 `( |4 G2 Z& B& W& Y AnsiString Parent;* f- {) r; {8 \5 ? for(int i=len-1;i>0;i--) 0 s8 J! m( R- F5 m# D2 {- D9 S {/ d6 G9 D- ?' _1 K5 ] if(Dir.IsPathDelimiter(i)). `* {( \2 L9 _ {5 A9 e- A4 o* Y Parent=Dir.SubString(0,i); 4 H( y) c/ K' p' { break; 1 `5 b9 \8 ?7 ^* r0 A2 O4 P) i }) n& J1 i; q& O }7 k- H& {* x" }2 g8 p* [ if(Parent.IsEmpty())return false; // 目录名称错误) H* U7 ~- G4 V/ n$ t/ K. j+ D bool Ret=true;5 p5 I0 X& n# h' A9 k, m. n" P if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 # w2 y; }- `5 p' Z3 b5 s$ u! g# t Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 # V5 f7 [3 ]7 E9 U if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 2 w2 N( U" {$ b9 m if(Ret) // 父目录存在,直接创建目录9 H* Y" I: G) |6 T5 l {/ }5 Y1 U2 W0 j2 {4 r3 @ SECURITY_ATTRIBUTES sa;+ E7 l8 Y" p3 |# H9 s/ c sa.nLength=sizeof(SECURITY_ATTRIBUTES); ) w Q8 o8 w2 T5 G6 A2 h1 h sa.lpSecurityDescriptor=NULL;$ i1 p8 i+ ^7 }" F4 U+ i' N sa.bInheritHandle=0; 1 |/ A! D( R- z2 B$ ^# w% n Ret=CreateDirectory(Path,&sa); 7 l7 T* T; x' w& o, H } 3 v9 p6 @* Z( z return Ret;( k7 e1 O7 I" e' G0 M# N } , m- Q1 `) K3 r. E 可以看出基本方法是:" |0 d; R5 |+ N7 |9 a, x 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; . C% S$ `5 q+ N% z7 t" r 如果父目录存在,则直接创建目录,否则自我调用创建父目录。

9 n& c- F; {, a h' B: v/ {( K) H/ R

$ |8 d2 E4 [$ F# O: J 四、直接删除整个目录:

6 T; p1 O6 Q% z& D+ a {

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

- l9 Z; P6 W" P4 j

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 6 t3 g* }: C4 ~" @2 s5 \4 z/ @. \0 G4 x 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 " P- I3 s5 I* |1 s* F9 Z5 H如果找到目录,则进行自我调用,即开始递归过程。 * s) A/ }5 O, I( @1 `) D6 F W 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 - J; G% c. p5 _+ T( | 具体程序代码如下:

- h: S* D" T" ~: d

bool DeleteDirectoryEx(const AnsiString &), a$ E7 P$ T2 k, }- ~# R9 O { 4 j5 Y. G; Z7 I if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白9 k, d9 C% G2 v/ u: I; [- v% y int len=P.Length(); * @! l: c# K& p! _# d& e char *Path=P.c_str(); / Z+ g6 D5 m, e# X8 `; \. f AnsiString Dir=Path;$ O8 i0 W4 J) }: X8 | if(Path[len-1]!='\\')Dir=Dir+'\\';3 h( f9 A- R. ]' J, g; n AnsiString Files=Dir+"*.*"; & S$ c3 o3 [7 L- L WIN32_FIND_DATA wfd; 3 p3 T" t6 e) y( J. \# A" W* c' y HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 0 D: }5 I3 c, {& r bool Ret=true; $ z/ x% z+ e- Z6 L AnsiString Tmp; & ~3 y" D p5 _% u F% a if(hFind!=INVALID_HANDLE_VALUE) 7 T& w. ?/ u9 {. H, {$ r0 [, n {+ I# h& ]5 m& {1 S2 y+ K. S/ X. P bool bFind=true;* g8 E# r0 Q* I. a4 J- Y while(bFind) * c4 ~7 b# j1 R* v {' [2 K7 W2 ?) r8 u if(wfd.cFileName[0]!='.') // . ..9 M+ g- d% F& c+ g( u( Z { # O5 f' \( ^' Q/ y5 } Tmp=Dir+wfd.cFileName; ' \( {6 `+ s% n, a9 w) e9 I9 k if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- r) x5 C* E% W( U1 A, |" U { // 删除所有子目录 ) A6 x K! A" w Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); V6 [. c& ? F5 }; O3 s }else/ I/ d3 R Y. \; f5 ]4 Y z \ { // 删除所有文件 $ M$ m9 Q, U" Z3 i& x% a SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);5 ^: i" n9 {( N1 V Ret=Ret&&DeleteFile(Tmp.c_str()); 8 u8 Q- D R2 a9 p; T% O! Q8 T8 ~ }# B5 F p9 r Z Z/ F* j8 N } " ]9 \/ w2 G S9 H# K; p1 d% V0 ]2 ^( W bFind=FindNextFile(hFind,&wfd);7 w4 N, @: ]* h8 V$ ?7 \# O, a }3 ?) w! O( J) Y7 s FindClose(hFind);4 e t7 |7 j% `1 b* z" e+ F } ( W% L7 n% O$ {! v; ~1 a* e if(Ret)return RemoveDirectory(Path);/ r8 W+ B. m2 {5 W3 l w! l" t$ Z' [. d7 x return false; 7 s/ x2 M1 L& F( u} a& V5 |+ O/ `; q7 [' E

- C* h" I; c: K/ H! y% J9 P, l

# q) F5 D- X; o5 u# I/ E: H* V7 h$ 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, 2026-6-14 19:07 , Processed in 0.456883 second(s), 52 queries .

回顶部