QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

/ x2 ?. W A& ?& W- C

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

8 {2 ]) j6 z" e' ]

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

6 o" v# ]5 P8 G- H) C

一、判断目录是否存在:

8 D+ r" Z8 L9 \5 `; ~: N

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

* w" p2 M+ Y' u. c: q% E

设char *Dir为带判断的目录 a: u( |8 _2 d3 E; G) Dbool Exist; // 最后结果,表示目录是否存在 8 x, T% p: B3 F4 O6 k1 E* Dif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”$ W! A$ Z% J! U+ Y/ j' c9 W! P! \, I WIN32_FIND_DATA wfd; // 查找5 E3 i U% _$ G, I HANDLE hFind=FindFirstFile(Dir,&wfd); 4 Z1 }& U* C* b' X6 ?0 p6 T" i if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 / V7 B% v4 P& l1 ^, {else1 H# r. z1 d, Q; t9 Z h8 O q {$ Q, k9 W/ ]! K- m$ {0 k if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 7 ~. y5 g+ X+ Z- Q/ ~+ _ Exist=true; // 是目录,目录存在 : w, Z* p: f/ L+ t: J else) o$ T; z' i+ s0 Y+ a" |$ ^% n Exist=false; // 是目录,目录不存在 ' G+ [, X% L% G1 \ FindClose(hFind); 3 u2 W. Q( E# t( g# f' g5 W}

5 v, V( u, L: D" U

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

/ W8 G9 f7 y" a: w: X7 @3 y

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

$ O# G' }+ M3 h/ `' `( a

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle / Z2 D% ]5 u2 x) e* VLPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL 6 _1 h9 ^6 x! U& a) _LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 ' D, {0 T- R* T8 `! ~LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 2 m3 ^# ]: d* w UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS ) |3 v! L- ?; j! y7 ~7 B: d4 ~BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL & T' X& v5 r2 c LPARAM lParam; // 预定义的对话框传递给回调函数的值 ) F8 Q3 X V. w* t/ Kint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 % \; S" a5 g1 }& E+ Q 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: : P8 A3 Y% j3 R4 W$ X! v #include <shlobj.h> // 必须包含的头文件7 G' s ?6 K$ H2 ?% e* p9 g char SelectedDir[MAX_PATH]; // 最终结果! B2 C4 G. d& }% f BROWSEINFO bi; // 入参; e6 ?4 x( G1 y1 J char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font ! z" D( ~; k X% C( n) u8 S+ WLPITEMIDLIST ItemID; // 所选目录的系统标志指针

$ c$ I" G# A, Z z, S

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果5 U$ r6 @9 ]: D5 z+ p$ T memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据% y$ C) @ U0 ?* t: h% G0 G& h bi.hwndOwner = Application->Handle; 8 C/ t3 K6 A# \6 F4 dbi.pszDisplayName = FolderName; 7 }" x5 S9 s# j( hbi.lpszTitle = "请选择目录"; // 改成自己希望的 ( ]# K1 n! n+ x% P; Wbi.ulFlags=BIF_RETURNONLYFSDIRS;4 T$ v9 B4 s- ]( `3 T ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框1 G1 U6 ?1 l$ N) S: j8 {9 W if(ItemID), L0 p1 ^* J' J# _ |4 W { & F3 [4 n+ f U: P SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名( `( ^) f- W B- h- h% [" s9 r! M GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 ' Z$ k# u; r# n}

/ l- i- S! J9 ^# {8 i" m! i. b

三、直接建立多级目录:

. o# ^% t, T! n8 B# @# R

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

- V& b: _0 Z- H H. d

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"& U# y) j) b2 n9 H% B" n8 w, K {6 H% z: y% U# x% }3 O) d$ Z if(P.IsEmpty())return false;3 F t) W+ x _3 {* r int len=P.Length();8 w1 k( P" r# u char *Path=P.c_str();, n7 a+ |" J1 f( Q7 d9 _ if(Path[len-1]=='\\') - m+ R' c5 ]& j9 I7 q { ' c2 ] ?) _; R n& _0 O* `' }/ c len--;' X t2 ?! F: X; d! ] Path[len]='\0';' H( K# [0 q/ Z& q q) H" P } // 删除末尾的"\"8 r! l+ O, E( `! T% A( [2 r( S AnsiString Dir=Path;' y9 m, ?, z: w# _ // 分开父目录和本身目录名称& Q9 f$ ^0 D2 ~% b& K9 { AnsiString Parent;) D1 M1 N0 r* ]$ W for(int i=len-1;i>0;i--) 8 \+ y8 v) d3 J" d4 P8 j { . U5 h1 x2 E; B& {0 r" Z% @ if(Dir.IsPathDelimiter(i)); P. h3 H o3 I" d) M) S {2 G4 d, M) ^# I5 Y Parent=Dir.SubString(0,i); / s) `1 J* z. u) k& Q break;5 T1 h8 }+ h9 K+ J) k: V7 v. p4 P* ^ }3 f# c! v1 Q! r+ ^, C2 `, u/ V0 C2 M } - x1 s5 ?6 H( Y9 y! l if(Parent.IsEmpty())return false; // 目录名称错误/ y B5 b" B3 ^" r bool Ret=true; 5 P3 d* ~: y7 H8 Y; {/ ? if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 * s5 b! I! N; {4 w5 [' B Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在) l* l) b5 T- c% n/ Z if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 4 }# ?- w2 v5 S4 ?& Y if(Ret) // 父目录存在,直接创建目录' ~. m/ s7 i r1 J {! d5 M- h& Z* K) a+ [# I% M& v8 } SECURITY_ATTRIBUTES sa;7 y( b0 X; R( b, B' w" I* X sa.nLength=sizeof(SECURITY_ATTRIBUTES); ) f$ l# Z5 v: |+ h% I sa.lpSecurityDescriptor=NULL; ( U8 z. k4 @; Y9 o& | sa.bInheritHandle=0;3 Q# X1 r2 ]; ^! A% R Ret=CreateDirectory(Path,&sa); ' E! k; l( ?( |, P, Z } m# h7 a/ z' s# ]4 V return Ret;% j! q1 v- N# a" u/ H7 v } $ l' B4 k" W! O L: u 可以看出基本方法是:! j6 c* K5 I# G" ? 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; 6 N; x- i+ E- a" ~' M& j. E* T; h如果父目录存在,则直接创建目录,否则自我调用创建父目录。

' M* }) J7 J5 l# E9 w& k I

' t3 q; |3 m- U! B9 O% W ]2 e# c" l3 v8 ^ 四、直接删除整个目录:

$ |- J1 |* Z) o7 l; W

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

# J; c8 Q* H5 P

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) ! J* @1 b" s# e X, C 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 , A: w- G* P; z6 B* J 如果找到目录,则进行自我调用,即开始递归过程。 ) h: n6 q5 J! s& q; Z如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 G% |: v' Q! m! P2 H& v1 j: R( L 具体程序代码如下:

5 [5 [ O0 ~$ X2 J4 j0 u

bool DeleteDirectoryEx(const AnsiString &) 7 I, V9 ?! e* H* T! ~& d+ A{9 H: E. S ]4 F5 d) V( N6 v* w if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白/ |. A) H: H/ }- y. _' @7 l( o( s int len=P.Length(); ; }% R5 Y# h2 n( W r char *Path=P.c_str();$ j8 m2 l- P1 h$ Y, n$ T9 M AnsiString Dir=Path;- M0 S% f% F& G1 ] if(Path[len-1]!='\\')Dir=Dir+'\\';2 H& L) d7 Q' S1 M5 z% }# F# F4 K AnsiString Files=Dir+"*.*";+ {4 u) e; s7 ~4 Y WIN32_FIND_DATA wfd; ' E' |: ]* @, ]# a& \/ w @' K HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);8 j; S; B% Y7 l( F. n bool Ret=true;* E) F$ V, u; n0 z8 X5 z) i AnsiString Tmp; * m* W# J5 y3 `( l2 s! J; c6 Q if(hFind!=INVALID_HANDLE_VALUE) ! X. \& B8 }/ c { 2 T" }8 A5 Y" \ bool bFind=true;& c; c7 a* @" K1 v" Y while(bFind) * L9 a2 ?, s' F0 K" t) j/ o { # j+ B' E8 g" j l4 r8 A! ~ if(wfd.cFileName[0]!='.') // . .. 5 t2 d1 r7 r) m { V' u; ?- I( [9 T6 a Tmp=Dir+wfd.cFileName; + }# t3 ?. Y. v7 {7 x4 W if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)* W4 _4 r u# ]! w+ D( T6 \' z9 e! b { // 删除所有子目录 $ d2 U |# B& Y) A: m" R0 v Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);! C, V- u. X K7 e1 H }else" \$ E+ T) M `8 Z$ r8 Q+ {) \3 R { // 删除所有文件, F$ m+ @6 J& s' a% G/ j; F SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);7 ] ?5 [- f; D, x, ~& c Ret=Ret&&DeleteFile(Tmp.c_str());8 Z- w0 R, t; ^. s5 p+ z* l }: j) a5 L8 @$ p; y) `' u% H; _$ t }8 T: c8 P" `9 n$ z1 a- r( G bFind=FindNextFile(hFind,&wfd);! u3 C6 O$ k1 c5 z' f: b! D } 1 z+ D3 v* J. z- }* V. R1 i FindClose(hFind); ; D0 X( w; y [( ]3 l } Y! M& | ~ J if(Ret)return RemoveDirectory(Path);% z" V% A1 G3 o2 x return false;6 O8 G$ S. w, O, u6 S } & D# i" h4 G% m$ o

& d0 W7 x% p0 D

5 A2 W2 Q- R' W5 ?

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-7-12 00:31 , Processed in 0.434950 second(s), 51 queries .

回顶部