QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

/ g* v7 X$ P- }

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

3 O- u/ y9 t, s9 K

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

0 }+ z9 Q( F0 I. D1 z

一、判断目录是否存在:

! L! Q4 p) ?9 v# |2 _

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

& v* I2 l$ t# v2 L! T

设char *Dir为带判断的目录- T2 O }) C' K. e |9 B bool Exist; // 最后结果,表示目录是否存在 5 z2 N3 X: h) c @if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”1 E2 z, H/ F' S WIN32_FIND_DATA wfd; // 查找 ! a$ W+ _7 O$ w! P' F$ X! BHANDLE hFind=FindFirstFile(Dir,&wfd); 2 `) p9 g% [1 K, H1 O8 J; U* J if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 . m+ K2 M* F2 ]7 `else / ^. s w$ Q* z: P0 _: [4 Q{ 6 p1 Y4 k8 W# r3 w N if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录9 n* u* {- k- b, _4 f Exist=true; // 是目录,目录存在 & t5 D. ^0 }) [ else / f2 h; @% _6 x0 r, d4 D9 i Exist=false; // 是目录,目录不存在 6 ~" h! |. F% x2 s FindClose(hFind); * n F& }) @6 a/ T: ^}

+ P( V' p8 g K; K

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

% [2 D! j& Y! @- {$ v" w

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

* ~& n, o' |0 m! q

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle ; D& ]1 K$ h" R! _. |- ALPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL & {/ _0 L( B8 \! V6 X- nLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 , y6 g7 R( c$ Z! s" Y' y# ]LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 9 e Q6 ~, c3 ~+ tUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS p. Q: ^1 n$ wBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 7 d: a/ @; E! B7 ~0 R, H LPARAM lParam; // 预定义的对话框传递给回调函数的值 9 [5 {+ N6 i4 ~int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 0 C5 Y6 ^6 k1 @6 A2 H 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: ; Z7 T4 [8 B. ^6 M6 y+ P6 o#include <shlobj.h> // 必须包含的头文件- t" a+ o* X0 ]% d char SelectedDir[MAX_PATH]; // 最终结果$ z4 @ Z( }* }3 L3 c BROWSEINFO bi; // 入参 % G' s7 [$ ]. `& K" \6 {/ e. Cchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font - @& q! f! I" t3 i) m/ L LPITEMIDLIST ItemID; // 所选目录的系统标志指针

8 H Y# ~ p6 _6 z

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 / C3 ^/ ^& m* g& Z5 C2 Wmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 4 d0 l# F7 Y. _" }bi.hwndOwner = Application->Handle; 2 i% @( @8 L" B* ]bi.pszDisplayName = FolderName;' i. g' g7 N- I1 }, D4 I9 U. x bi.lpszTitle = "请选择目录"; // 改成自己希望的 4 K, {( W- O3 T D* L- `bi.ulFlags=BIF_RETURNONLYFSDIRS; 5 B8 i1 E/ D( }/ U. GItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 ( @, C+ J1 h' l! e6 @if(ItemID) # U; j1 ]* B( Q/ e{ . V/ b+ l. w6 x SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 1 k# Y. w: ^) D1 s GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放" W, X7 |. ~1 n$ v5 r- z }

* V" C' g/ _/ ^6 B* E' P

三、直接建立多级目录:

& }$ I6 C1 X8 ~: G3 R+ M

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

: S0 x7 h! P: z4 K, L

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" 1 ]9 c% ^) D" c3 e: O{ : W4 f& h( U' S# \( _+ G4 O6 w; d if(P.IsEmpty())return false;( J& s5 J) U4 A% A7 ?, k int len=P.Length();1 n; ^% }- ?, K9 S0 K char *Path=P.c_str(); 2 i R7 e9 t/ O; _' c4 ` if(Path[len-1]=='\\') * Z8 s7 e7 a- [. ]. F, E1 ` {- }& ]3 q3 g9 i9 W len--; # v8 ]2 d: a& Z0 `% ?! m Path[len]='\0'; b# I1 T- [0 U9 X9 T+ G } // 删除末尾的"\"& Q$ J1 G3 o+ L0 g# V AnsiString Dir=Path; 9 W1 p% b" I6 Z9 w; H+ C- x // 分开父目录和本身目录名称7 r8 P8 d& x2 F$ U- E. A AnsiString Parent;& x! U9 A# W" E$ r for(int i=len-1;i>0;i--)) l$ o4 y1 n! C Q { * I+ ^) R1 R+ v0 {, L1 D) W1 |+ P if(Dir.IsPathDelimiter(i)) ! P9 {, S' } L7 K7 ?% [# `; \ {; m E/ K6 @- O9 j) X5 J2 Q Parent=Dir.SubString(0,i);2 G6 n+ W' P; }7 ^ break;6 R+ ?' W K8 f: Z: | } 4 @' m3 V8 W9 A0 @- r- @ } 5 J7 S, o) B* [ k if(Parent.IsEmpty())return false; // 目录名称错误! M7 i/ R9 K3 h6 X2 Y- r bool Ret=true;+ d! l9 T7 o0 \8 N- ~ if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 % m# H- I. x$ ^; n Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 . w- H( h3 Z' j6 Z9 p- ` if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录8 T1 D0 h* F5 B5 ]8 p if(Ret) // 父目录存在,直接创建目录) A: Q8 y/ x \% {1 m- Z9 {' n { ; ]* x: J& ]6 g SECURITY_ATTRIBUTES sa;! [4 D3 p2 g: H/ b$ I4 j sa.nLength=sizeof(SECURITY_ATTRIBUTES);, @9 k6 r" T& v7 y% Q( a0 v* w sa.lpSecurityDescriptor=NULL; & T( J$ p; A8 U" E) X f, e- F$ G# Y sa.bInheritHandle=0; 1 e+ a6 {, W) e! n* Y Ret=CreateDirectory(Path,&sa); ( f5 l" S8 i9 j$ b& b- y } " u* b5 l& A/ q return Ret; 4 }4 v% f2 Q* s} ( n6 q* {7 X9 _ ]8 l 可以看出基本方法是: ( N" q# i S* ]& C) w* t; m. [先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; : x2 {2 h/ t* B4 X1 ^ b1 H如果父目录存在,则直接创建目录,否则自我调用创建父目录。

6 k- h0 w: D! r, f# W

" F; V+ Q G# D& k9 o# I四、直接删除整个目录:

# P, e* L; ?* n4 P: S) Y

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

4 \1 U5 j. B& [) b' J

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) - y+ P" r% Q+ ^+ h! m6 |4 L% U- D' } 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 . H1 N2 r+ t# V& ~1 b. r( t- S如果找到目录,则进行自我调用,即开始递归过程。 ; F5 s r* r4 ^) ^+ M# H/ Q如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 4 I; Z: ]% d5 \, a具体程序代码如下:

/ d3 h5 U/ a! L/ x/ I

bool DeleteDirectoryEx(const AnsiString &)2 q- T6 d' Q% l2 c {" L1 o7 r! K8 _ if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白1 Y+ I8 H/ l% W5 l) i* m6 z int len=P.Length();/ m3 C/ u( Y7 j; P( j1 s0 j char *Path=P.c_str();0 |6 U, A4 g0 r u2 X' \$ t4 k AnsiString Dir=Path;( j. }( n6 B! x/ x+ [, V" r& T if(Path[len-1]!='\\')Dir=Dir+'\\'; 3 w$ F' r& j; V' Z' Z AnsiString Files=Dir+"*.*";# F9 Y) M3 c4 C( h) U* } WIN32_FIND_DATA wfd; : J& Z0 _' G( u" A HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); ) K; w7 z% L, E- j- z. @ bool Ret=true;' E/ r7 S6 U( ~ x' b! D AnsiString Tmp;7 M9 u: K/ }8 T* w; \ if(hFind!=INVALID_HANDLE_VALUE) 7 e" A- ?, [2 {4 G# e& n. |8 u { , c. O; F; K3 ], h bool bFind=true; 2 K$ W3 I f* V8 q# G while(bFind)4 E) t, n, `1 G; N3 d+ y { ' Y$ Y5 y9 D; t, V9 G if(wfd.cFileName[0]!='.') // . .. / [! c" H U( f6 E, \! H7 ` {& u D, J, [' t0 d; p) s9 A Tmp=Dir+wfd.cFileName;5 ?( b; Y2 L C" q3 _+ u if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); h' j4 }- E# G8 R$ T { // 删除所有子目录4 G) b5 U4 N7 h# O Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);* o: n! \# r, O! \" n. F }else 4 q$ K B. Z c1 [/ p$ d { // 删除所有文件; H* g( a, t; l9 k SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);9 v4 _# l5 x0 H* m& t' j& A Ret=Ret&&DeleteFile(Tmp.c_str()); 0 h+ @* a. X! V, I. [$ M } + w: p& ], S6 ~ }& }8 D$ @ a& ?/ X! L9 F; h bFind=FindNextFile(hFind,&wfd); 1 H+ m+ S7 t' K" D } % q$ v/ H; {. G4 K FindClose(hFind);% T; F) e0 V8 j! o* S } # h* J j6 w, E! m, x if(Ret)return RemoveDirectory(Path);# z/ c p# F1 v1 `7 ]2 r% ? return false; 5 o4 b4 t' q5 U} : \& d* d/ k2 i6 v+ g

Q4 m4 ~8 l K' s7 a, H/ z8 ~

6 [( I. r8 N; d: E/ t

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-8-17 15:32 , Processed in 0.490968 second(s), 51 queries .

回顶部