QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

( q: f' W, _' C' T

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

K' x" |1 r" D5 R8 Q

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

- Z. B) ~8 }( `8 G& X! c

一、判断目录是否存在:

* e4 L+ U7 Z( m5 k _

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

: B9 |/ b" P" g, T

设char *Dir为带判断的目录# p/ f: d. y8 m( ^2 _5 v! A6 \. y% a6 l bool Exist; // 最后结果,表示目录是否存在 9 g) F$ L" ^7 tif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” A% p4 A% d' n; e$ wWIN32_FIND_DATA wfd; // 查找 ) l( Z1 s G9 t' I9 S! P @HANDLE hFind=FindFirstFile(Dir,&wfd); 4 L A/ q' A- w! sif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 ! b' l( e2 N4 x, W8 J% nelse9 U: J* ?! y1 M: R { ' k- R; F7 E4 j' w) U7 _: T if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 / Q6 E% V6 R% d3 U& z Exist=true; // 是目录,目录存在 ( Q9 c3 w) i: Q; N; e1 x else8 v3 I; }$ m& c8 X9 C9 J Exist=false; // 是目录,目录不存在 9 ~! a- o6 Z. W FindClose(hFind); b5 i3 t& A5 B) C( F& z }

" G( [2 Z% |& R" h# c2 E e0 C$ y

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

2 P/ V2 z4 i3 I" s g5 O' ?2 `

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

% T) A8 G1 b# Q: R J7 n& K( o

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle l/ j# g; ?9 X: U) T7 B! s LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL ) _ j W5 k$ s! e9 ALPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 & n) _0 x6 s7 Y! M3 O" S* u9 m* ALPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 5 c6 B0 n* ]$ V! oUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS % F/ K9 Z7 A9 e: S& B `3 q BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL + l6 a6 E; z" ]4 C, _9 d6 @LPARAM lParam; // 预定义的对话框传递给回调函数的值: U8 V' l3 M0 r/ D int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 0 L# J# ~; l+ l% b) h* J5 D- d可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 1 z- e. K: U @) ^0 `, u7 Y #include <shlobj.h> // 必须包含的头文件 7 b- U: Z4 E4 b: j9 {7 E9 u' w" Nchar SelectedDir[MAX_PATH]; // 最终结果 j, x- f# t( f3 L5 b BROWSEINFO bi; // 入参8 T+ C' V% j6 z char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font / m0 q: C: b, C' w# K; @LPITEMIDLIST ItemID; // 所选目录的系统标志指针

( z3 r! u$ h5 [# T& U5 D/ [

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 : z# e1 D" ^! d# F, V5 qmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 6 W0 |$ w. F+ c3 m+ v* ~& fbi.hwndOwner = Application->Handle; - N$ F0 H5 d/ B _0 N) }5 m! P" Zbi.pszDisplayName = FolderName;. l( h( a1 Y- A+ j0 q j bi.lpszTitle = "请选择目录"; // 改成自己希望的 * x$ y/ k. B6 {1 a- i) [( ^bi.ulFlags=BIF_RETURNONLYFSDIRS;6 Z" P; @8 B* E0 Y5 Q7 T' N* H ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框6 ^4 f3 v" L# z! [$ Y if(ItemID) 7 R* F) V4 T" M0 X5 c# k* F{/ `4 B3 H4 [3 I( P SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名! ~3 e; q+ D( d' \ GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放1 ^. L& s: c1 U# \/ ` B& I }

" K* V" t& @% ?( H

三、直接建立多级目录:

- ?- Y4 M ^/ K9 T' |

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

8 c! M3 A9 S2 J6 [9 E

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"2 `) A; g4 e, |# G; m {0 N9 ~' o, M0 o if(P.IsEmpty())return false; & T- {+ z6 b6 h& W( K7 c0 ` int len=P.Length(); 9 a* A- d6 e. H2 \ q: F char *Path=P.c_str();/ m( f( d8 ~% v5 ^! n5 Q# B if(Path[len-1]=='\\') / `5 E& a1 L9 q9 z {6 X7 `! D# M3 c1 D# J len--; { ^4 G: l" q H- c* g8 a Path[len]='\0'; 6 I4 V% z% i* H- u0 X$ v } // 删除末尾的"\"6 o# A3 c) e6 t8 Z AnsiString Dir=Path;/ F4 s) @5 u; ^1 N // 分开父目录和本身目录名称 2 H8 C) N# O# _/ ? AnsiString Parent;- ~( B8 G! X, K# a8 P2 ` for(int i=len-1;i>0;i--) 5 l+ M, \' u' ~0 E; d. o! u( S9 C( i" S- A {7 L# ], B, ?0 x if(Dir.IsPathDelimiter(i))$ A9 N( k* q' M; k { $ K& y" }% J( p( Z Parent=Dir.SubString(0,i); 3 C3 q$ z1 z% _5 w break; & \; F" @5 y8 r, { }) j9 z, e, P6 L6 I! p6 E }! {6 _, f J3 X1 H( u, Y2 |; a if(Parent.IsEmpty())return false; // 目录名称错误 , J& r, \: Q4 g) x# e4 F7 h bool Ret=true; ) `/ f3 Y! r- ]/ W if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 6 J: g# K r' l/ E1 c+ v! X, p; J Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在" |$ i/ R! ?2 k if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 0 C' O5 k: L% a( ?+ w if(Ret) // 父目录存在,直接创建目录 . k2 s, X2 t' S' ?, U { 7 Z0 |1 w0 Y* q' a3 h+ N& V9 ?& d SECURITY_ATTRIBUTES sa;, z' I! r# |. P3 s3 s sa.nLength=sizeof(SECURITY_ATTRIBUTES);- u$ G5 t1 o! W; T sa.lpSecurityDescriptor=NULL; 0 \# v3 V2 i) U, B1 z- `7 u sa.bInheritHandle=0; ) [7 f" Q r1 Q Ret=CreateDirectory(Path,&sa);6 C! |) F; x* z2 B } 9 \9 l p6 E- }& M: t! E9 F! ] return Ret; ' Q1 N: i" u5 r} a; Q. ~2 G1 z5 x6 W4 @; t* @ 可以看出基本方法是:/ s s7 r8 J0 ]& G ~$ J6 n3 U0 T+ D 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; & G1 N( R/ e, q& i# v) y$ P如果父目录存在,则直接创建目录,否则自我调用创建父目录。

# W( j3 m, K0 R& y4 @" y

0 A8 G, N% g- G四、直接删除整个目录:

% w3 H! u! t3 e5 b, x3 A+ J- Z7 ]# q

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

) N1 X# U' l3 ]# f& A

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 7 U3 y, E7 d V% e3 V 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 : q1 k% P" V' l# |! ^. J如果找到目录,则进行自我调用,即开始递归过程。 : e! I2 {% W* } 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 9 C+ v- G B4 ~: i! f具体程序代码如下:

0 q. i! W. u, r( g/ O3 `9 M2 \4 y

bool DeleteDirectoryEx(const AnsiString &) 9 ?) h5 H) k) b% c{% N3 h- V. m' B8 y0 t2 ?; C! W" B4 M if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 + r! [$ c/ z8 m int len=P.Length();! ?8 t% X) J! i! q# b: ^ char *Path=P.c_str();, ]$ E( W' C2 J+ ~ AnsiString Dir=Path; : s8 P* i7 Y- Y if(Path[len-1]!='\\')Dir=Dir+'\\';& G _) W3 Y, k0 s' r, h/ ? AnsiString Files=Dir+"*.*"; 4 v+ F1 `" i8 o8 H- }* b9 A WIN32_FIND_DATA wfd; $ @7 Z. i/ ^6 Y% H HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);5 j* F% |: I9 J4 V2 [, U! y8 w2 L9 F bool Ret=true; ! o1 f) T: Q$ i$ Z4 J AnsiString Tmp;( b2 B6 {, d" t$ m% S3 ~* I if(hFind!=INVALID_HANDLE_VALUE) " S; `& l8 c2 {; I/ z, b {- @9 v2 S" T+ ?. I3 c& L bool bFind=true;' l$ e) X2 k- i9 |' D2 M' Q/ {# @9 Z while(bFind) : |! ^- p: G" @' O4 C: } { " Z! y& h" J3 N! y0 E; E6 r" H if(wfd.cFileName[0]!='.') // . .. ( Y- a. ]! C3 R: W' ^ { \" i- U* {8 J/ E2 f5 l& o Tmp=Dir+wfd.cFileName; % S* P2 z, \! F: K) p if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)8 b9 X6 C; C& L* j, V8 d { // 删除所有子目录& }' N3 |& r/ N3 r2 U! {& ]* u; v+ I Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); 8 T8 q4 Y4 e9 E0 G Y$ g }else$ E/ h ~/ @& U3 l' u { // 删除所有文件 # U, Q( J8 `5 b& W' p SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);- X. g# H) F3 N& t) b' c Ret=Ret&&DeleteFile(Tmp.c_str()); R* q3 a0 J9 h( c) \/ f } 8 ]8 z4 v6 x8 o! E7 U6 A$ d } y( G7 Y' Q( ]4 P bFind=FindNextFile(hFind,&wfd);- P5 K$ g8 H& }+ }7 A6 j/ J }) b* k" `$ P/ g; H( J" t# s FindClose(hFind);; l6 e4 W X6 t3 J( f" D }" D6 C$ m* U' [0 G, @7 _8 l$ t7 \ if(Ret)return RemoveDirectory(Path); ( K; d" U$ x% b% a) u return false; - j1 E; I5 l- N. F; ?} # f! V5 G2 {2 ~( }$ _1 r; y

. v7 [) o9 S" _4 P

5 T' J' D5 `& t9 S3 m3 P

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-8-19 19:47 , Processed in 0.333449 second(s), 51 queries .

回顶部