QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

' |9 ~$ S; p% c, q8 h

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

: a5 K* K0 {5 t3 s; b/ g) Y' d

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

+ S4 K" c; _( q$ D0 Y* C+ Z1 J

一、判断目录是否存在:

0 z( |8 s3 p- E5 b( ~+ }3 c- C' w( z- v

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

5 Q: v: \& j8 W. j- a( g

设char *Dir为带判断的目录2 p9 c. Y, F5 Y% _: S bool Exist; // 最后结果,表示目录是否存在2 a' K* A8 z- n- a0 L& M if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”9 A- Q! I3 e0 i6 f; d! B WIN32_FIND_DATA wfd; // 查找 ) B3 L! B- p" S6 rHANDLE hFind=FindFirstFile(Dir,&wfd); , T: K$ y8 G- d1 ^8 o+ Q8 D/ \ if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 - B* @& d" C6 @$ X5 W1 V) {/ Q) i5 Aelse ( {# d& @" c* t: b{8 }1 N% a6 M3 E. C if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录3 I; d% A4 A" v, V9 V$ C- P! a Exist=true; // 是目录,目录存在 ; z* t7 c0 r( q1 I" l2 g! k else: q& F7 M+ b/ h! G Exist=false; // 是目录,目录不存在 # N W' a3 v# N) Z! O+ \" F FindClose(hFind);! i3 D h! @( s4 o }

- j9 V# L; w4 m

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

* g1 T: y. h M( x; h+ Y2 a

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

% A3 Q0 F/ D& r. e# U0 L: T9 `

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle B6 w, |0 b \- q' ~( k LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL0 o$ l) w! G# k. |' `8 ]. @ LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 / C( F/ P% d4 P/ W" oLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 % ^9 e2 P0 o1 U6 [ UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS 8 x" _7 I2 J9 p BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 2 q( G# v7 b5 d: D; g LPARAM lParam; // 预定义的对话框传递给回调函数的值 . D; U' b. g- Aint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 ' j# @0 ?4 ^5 _9 q E; c* d1 l, B' [可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: ! n, B! `' U/ L9 C9 V! ^- R$ t #include <shlobj.h> // 必须包含的头文件& d3 E! a6 |- U0 `, y char SelectedDir[MAX_PATH]; // 最终结果 ( R0 d( N5 @: b; e( m OBROWSEINFO bi; // 入参 7 {* \1 X( z& U' e7 C- echar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font ( X. V8 F1 q+ c \4 bLPITEMIDLIST ItemID; // 所选目录的系统标志指针

1 D+ `. }) U4 T+ }

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 , _% ?5 ^* }& ~5 z' W5 gmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据5 l8 @6 M6 s3 J4 B8 Z; g2 { bi.hwndOwner = Application->Handle; " Y) m- N0 k/ s2 [8 M% V0 bbi.pszDisplayName = FolderName; ! ?; y# d: T- l/ g6 W) Sbi.lpszTitle = "请选择目录"; // 改成自己希望的2 ~( x4 c- l% v" r bi.ulFlags=BIF_RETURNONLYFSDIRS; % b+ i* k: @5 pItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框8 b1 b; p" x @: b, ?, _ if(ItemID)- e# t- f. ^) y9 Q" y' X9 G { k' N( K' ~* \( a4 { }( r SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名5 I) q- r( [( H: X4 G GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放) {4 Z3 W9 b" }: [ }

9 Q; F; `) ^6 ?0 J- n- c$ N; U4 ~% D

三、直接建立多级目录:

0 i& i9 {3 u4 |8 M a" v

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

3 ?) [) i& S$ D% j. G n

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" & ]" _$ b, w1 B8 E{ 6 {6 W0 X& x) G( c" F! D if(P.IsEmpty())return false;7 r3 x y, s7 B3 i& O int len=P.Length(); " E2 l) q! }& |5 n8 m char *Path=P.c_str(); 8 _% d2 R; R( t. Q if(Path[len-1]=='\\') + c) R: q1 l7 Y2 W" i {/ V/ [8 i! P% Y. k( ?1 m len--;" T. j# e' `# M$ [4 e! k% A( t Path[len]='\0'; ! j9 ~* B- n5 m. P" F+ K2 K } // 删除末尾的"\" 8 `# O( A* U1 h7 z* C9 B( I: D6 J AnsiString Dir=Path; 6 R0 ^. P, Q& v0 {6 Y) w9 H // 分开父目录和本身目录名称& e$ Q' y" j Q$ a5 ~ AnsiString Parent;/ l$ c# N( G( v% f for(int i=len-1;i>0;i--) % T" c, R5 \; ~: i8 j. M {# a1 K+ E4 B( M3 z5 ^/ M if(Dir.IsPathDelimiter(i))% v4 R, u4 Q# w6 W" ~9 P {% E4 u& H/ k: e4 G Parent=Dir.SubString(0,i); # j3 G$ S4 {% u; ^4 i& W a break;" `0 `( V5 {. t } 1 S+ `2 ]% p* Z( |3 w% l/ w } 9 U1 Q9 E8 Y% A5 w( ^; w" ]% K if(Parent.IsEmpty())return false; // 目录名称错误; D# w4 ~3 Q& k. j) A4 z. r+ F bool Ret=true; 9 F; G; z- ]) O% u if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录9 K& R& [, P2 Y1 [. `) L Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 r) A6 @( j! v2 y4 m if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录! K! Y' T T! ~! r) I if(Ret) // 父目录存在,直接创建目录 " n# s3 K1 i3 h$ S4 H; p {7 c8 O& \" D3 I, Q0 S' B |1 u* z SECURITY_ATTRIBUTES sa;' g: t% T3 f) s! e9 b sa.nLength=sizeof(SECURITY_ATTRIBUTES);1 j% k* ]; p; [! @6 {, Y }0 L sa.lpSecurityDescriptor=NULL;/ C' k! S2 V U/ O$ J sa.bInheritHandle=0; 2 f5 ^ X1 A& Y$ c" k Ret=CreateDirectory(Path,&sa); 5 P% Y2 x$ }8 U& L8 q, O }0 V% O* }: _8 p; D$ W: V6 U return Ret; - N q0 [0 M- J; U} / k( ]/ H; o) G) @# v/ l 可以看出基本方法是:9 Y) z- r6 Z7 y* |7 {9 V( Q4 c 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; ( V$ `9 _$ @ o. u如果父目录存在,则直接创建目录,否则自我调用创建父目录。

" r/ G& D" m4 Z9 F7 D: B! Q

' |, z z1 j. u& S4 F# a 四、直接删除整个目录:

2 F+ p( T% E& s) K

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

( J! Y% _* l. j

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) * Z" N# O' f+ m! f* K( Y 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 - U' H# ` d5 x: P; Y如果找到目录,则进行自我调用,即开始递归过程。 " s8 s8 [% e1 j. x1 y" E& h ?如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 0 j) s6 h8 l2 I3 G* Z具体程序代码如下:

: ~; c" A& y1 u( G8 Z m/ N

bool DeleteDirectoryEx(const AnsiString &) P/ S: }& k- {8 G( \" w{ : I% y, N$ y1 |0 R, @4 n- Q5 l if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 0 M; q8 Z; i U2 S2 D int len=P.Length();" X r+ Z7 k% ?5 H3 I char *Path=P.c_str();2 ?6 ^8 R4 T$ r' X# J AnsiString Dir=Path; ! s5 I9 i, K! l) l4 ?3 w/ w/ ~. i if(Path[len-1]!='\\')Dir=Dir+'\\';6 E; F3 a) y3 ]" h$ \# t* B$ \ AnsiString Files=Dir+"*.*"; . D- N7 d! T# C2 ]/ S- i& k WIN32_FIND_DATA wfd; 1 H; L, t3 R* {# o6 a HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 7 x) T, p7 ^- |2 `* A, m+ z* i9 B bool Ret=true; 1 G+ E* y6 M2 S3 e) I' e AnsiString Tmp;+ e, N ^: z N, Z/ b if(hFind!=INVALID_HANDLE_VALUE) y1 ~ [: }- ?9 b5 v {. \. `6 b2 g8 G) x8 C bool bFind=true;+ P$ _: c; @- M7 ?4 l) i. M while(bFind)- V6 z$ W/ `1 w: W' O/ m {) i) N& o+ l/ ]7 N6 U7 Y1 I if(wfd.cFileName[0]!='.') // . .. 1 z, c, O" N4 Y$ p* F {# O8 z: z- f7 D P9 U5 q Tmp=Dir+wfd.cFileName; * k. B @. ~' f( E8 P" Y! R/ K/ \ if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) m5 U: q" V% D' Z a { // 删除所有子目录 % j+ a$ J5 @" @( j+ v7 h9 Q Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);+ k( p7 M F& V }else ; A3 m j2 G0 I9 C" ~! W { // 删除所有文件4 }4 i- O# R/ g SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);1 a, F7 g/ c% s& ^! ?. M Ret=Ret&&DeleteFile(Tmp.c_str());. D: J' G1 P& l( V* ?* A }8 t+ m# W9 n) P }6 h# w o3 d" o- r! ^/ H% I% R' E5 j. w bFind=FindNextFile(hFind,&wfd); ( k9 |4 Z$ K6 F* J; o }2 o( n7 {& A* F. n FindClose(hFind);7 q) f! `/ Y+ H+ V }$ l3 ]6 l% @2 V3 I if(Ret)return RemoveDirectory(Path);: v0 n) e% A: @# W! P return false;6 h$ b( f5 Y3 {2 E% b/ U } / B$ x8 r. {* p$ I' d5 ~ w4 `/ p. t

3 y- M" N, x6 O7 I0 a9 b: G+ _+ u: Z

! G/ l @+ f, e1 C; h

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-12 01:55 , Processed in 0.458862 second(s), 52 queries .

回顶部