QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

% b) `' `$ e4 u

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

3 w1 ?1 \" n( K. ?. ]

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

C. ~% G6 C, t

一、判断目录是否存在:

5 w' y) L) I& |4 h1 |2 O" _

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

h5 D/ V( r# b8 C

设char *Dir为带判断的目录 ( m1 u( W2 G7 Xbool Exist; // 最后结果,表示目录是否存在 ! n6 }& h/ Y* o( X% _if(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” # E+ v; I, E; c9 X$ k6 G. N: i& cWIN32_FIND_DATA wfd; // 查找 5 I+ }9 j1 {8 h+ sHANDLE hFind=FindFirstFile(Dir,&wfd); " x0 T/ g3 s( ]9 F# Aif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在( A% ~8 `5 e& H6 n+ k- E4 z3 q else - d/ y7 }* E7 R- F) x{ $ D" `% y, [- n" ?% I- b9 r if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 / s, I( Y( b; F! a& o+ g: S Exist=true; // 是目录,目录存在 " e( ~7 z# O- A. m else! a; U. b# Z' Y$ k6 L- w6 U Exist=false; // 是目录,目录不存在 : j- P1 ?. Z! F9 ^0 t1 ~ FindClose(hFind); ) T2 b# _4 J4 y; H0 _5 N% I}

( G: A& w& k% [1 P8 T/ h

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

; s5 L" j- u; ~8 v' g$ F

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

5 _* S2 x) O z- a# p& J L

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 5 Y* t3 Y0 x: b! C' d U LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL + O- f7 y' v9 xLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 8 E- f+ g* q) n" E! J LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 5 x2 a# U2 m0 V& c: i7 x6 J; K UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS % L6 Y* V# @; Q& D9 RBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL ) L3 l! U2 F8 @) @2 kLPARAM lParam; // 预定义的对话框传递给回调函数的值8 J4 T8 I: Z6 t3 k' X int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 7 B/ L4 y9 k% V3 ]可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: % V' D/ m" H. B#include <shlobj.h> // 必须包含的头文件7 x( m4 V! B" Z! e8 r char SelectedDir[MAX_PATH]; // 最终结果# O6 C6 k: Z9 v1 n7 e P7 e; q BROWSEINFO bi; // 入参# f( ?/ ^. V- Q8 k4 z- X( O char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font 3 r* ~) O. _" N) H8 T LPITEMIDLIST ItemID; // 所选目录的系统标志指针

( D4 u, H& c$ n2 _

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果5 f* ^( J) N+ P4 o0 \; M memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 % l3 f7 K8 s" B. H, xbi.hwndOwner = Application->Handle; : f+ M4 O4 d- kbi.pszDisplayName = FolderName; 3 I; e0 i4 B+ g& F, {" k h* xbi.lpszTitle = "请选择目录"; // 改成自己希望的7 `7 x) b* _5 O bi.ulFlags=BIF_RETURNONLYFSDIRS; * J5 U! J9 x3 N# q" qItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 ! J, g9 r5 u, `( vif(ItemID) 0 q8 w) r* b# C: J/ d{2 f9 B5 t/ l4 k; Q; j# v SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 8 n" d4 A8 Y: I. }+ d2 | GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放$ ^- Y: Q7 a$ ]- O& `+ o }

2 j2 E3 a& @! Y9 k7 [+ G

三、直接建立多级目录:

! B7 r$ @$ q* p- }

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

9 a" X8 ~1 {1 A w6 x/ g

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"; {3 T: v7 {! |$ [. x5 U$ Z" n+ o4 } F {/ Z" ^5 `/ P x ^8 P if(P.IsEmpty())return false; . i- _0 P( H8 u; \ b2 F: v. r" u int len=P.Length(); # n3 ?, Z8 R; b n* q char *Path=P.c_str(); 0 d) s& O, ~5 F3 l' W if(Path[len-1]=='\\')8 E/ U+ L9 N ^! t5 u {0 N7 g' n5 x: t$ q' S9 R len--; * {1 \4 G/ I- ]3 a8 s Path[len]='\0';( R' Z B2 K1 [- i# x } // 删除末尾的"\"* q6 O3 T5 D4 \+ T6 Z2 i AnsiString Dir=Path;3 o2 ]% ?5 H# o // 分开父目录和本身目录名称5 c! f" X, D4 b! ]$ t" Y AnsiString Parent; 6 g o/ E( _; |: t h7 h for(int i=len-1;i>0;i--) 4 p6 E9 U3 c) U! }5 F { . A9 {5 t w& ?5 B1 y* Z: g7 T if(Dir.IsPathDelimiter(i)) 8 h/ i1 e* ]) j0 [1 m+ e { H4 y( J2 r& ?( F: o( p Parent=Dir.SubString(0,i);9 p9 ?3 Q5 @/ s break;, n8 m% h+ i7 T- Q- G8 p }; Z5 Y; q$ A. \! T: U } # V7 P$ r) U, }. I2 x8 H if(Parent.IsEmpty())return false; // 目录名称错误 # P" u4 m$ z2 \ bool Ret=true; : x1 L. \, ?; Y2 q8 n if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录& ~- v3 [" {- J# D+ o' \ Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在/ s4 P& T/ B/ y$ I4 | if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录+ h# O+ d5 W8 B2 Z8 m3 g if(Ret) // 父目录存在,直接创建目录 : g b- L) ]/ i) @( c { ) M6 ]- Q5 s. ^- C' L6 O% K" } SECURITY_ATTRIBUTES sa; j0 l& t, `: @$ y }: u3 W* ^ sa.nLength=sizeof(SECURITY_ATTRIBUTES);; o$ w! ] r: ~2 ?2 ~, g- Q8 @ sa.lpSecurityDescriptor=NULL; ! W+ s0 I* F# N+ t sa.bInheritHandle=0;" Q2 g: H1 o0 T6 T; ~ Ret=CreateDirectory(Path,&sa); 1 r+ ^" W2 T0 X; c } + J h& \& ?) F/ e9 S! H( n return Ret; $ X) l: g* i% T* d8 o9 J. l} * `& `( M9 f5 V) r9 v2 Q) ? 可以看出基本方法是:& j3 d0 }: G+ B 先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; " e" g: E: v0 n7 a9 F如果父目录存在,则直接创建目录,否则自我调用创建父目录。

* H" C* U, m/ R% N- K

9 b, i+ O9 z$ H8 V! p# s, W1 d 四、直接删除整个目录:

7 B G: n# _* v! v

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

1 I t$ A% X! X, E8 q

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) . j$ C, {, \0 ]6 X* z 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 8 ^& ?) i) v" Q! j9 H: @ 如果找到目录,则进行自我调用,即开始递归过程。 1 k. H% C4 H: p4 _ }8 L. d2 c4 z) I如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 # J+ K, c/ f# E9 Z: ~% b4 Z 具体程序代码如下:

9 D5 e5 B6 }! ?

bool DeleteDirectoryEx(const AnsiString &) ! w( p, d- D' k$ ~{ ; R- X3 L3 D# @8 G if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 1 E: f% ]" L- t# _' X* V int len=P.Length(); 0 f1 q5 o4 b, |2 t" ~! z# c char *Path=P.c_str();+ v% G9 @4 y# R7 o AnsiString Dir=Path; 6 [/ M. A3 O( ^+ d if(Path[len-1]!='\\')Dir=Dir+'\\'; - k- E4 k9 h' ^) d AnsiString Files=Dir+"*.*"; # W# k, z/ Z: g G) E1 x6 x( y1 b$ n WIN32_FIND_DATA wfd; # w5 Q: N- }1 c HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); . b, a9 i( E* O% t/ m bool Ret=true; ' _( b2 |) Y) q& a" |# l5 \. B: Q AnsiString Tmp; # w/ l Q) g0 R if(hFind!=INVALID_HANDLE_VALUE)9 z0 ]9 K! H6 c( Z# R! t2 W { + u8 G& X) e- Z% T5 I* K4 U* U$ x- @ bool bFind=true;- J9 t3 {/ S o) ~1 w: _( i while(bFind) h0 I) D( R1 O1 ^9 A* I {2 l$ B; K6 U$ g' ]( F4 L4 D2 A if(wfd.cFileName[0]!='.') // . ../ X0 e+ B9 _ J) a! w. E { + B9 Y0 E/ ]+ d$ B, q8 O Tmp=Dir+wfd.cFileName;* C- p3 w0 i3 ]4 J if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) Q' T% P* ?! K# P6 E$ S { // 删除所有子目录 % k2 K* Z& w+ [+ ?. a9 _+ U Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);1 t6 f/ `* q! W7 K7 a" E6 @2 j }else7 m9 e; B6 ?& p1 m# \; E) K { // 删除所有文件, t1 ?% e' [8 J3 {1 a$ t+ G8 y# ]3 ? SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);! C$ t. X- Y3 i- O6 t Ret=Ret&&DeleteFile(Tmp.c_str());4 E. N2 S. ^, p4 a( C } 7 @- H+ U. Z, A }1 z3 Y! d5 h. g2 a6 {! t bFind=FindNextFile(hFind,&wfd);4 l% a# a& V* ?0 g H } ; b- c; J3 m1 m8 K# ?) C FindClose(hFind);% f% Y9 N$ L* n } 3 h% x9 a+ z: q9 E if(Ret)return RemoveDirectory(Path); - U* X$ f+ ^" x# ]: r# s% Y return false; $ W& o+ O, Z6 _/ ?& F- P} ! ]' y% {! Y7 p, h9 j0 [

6 m' K2 X+ i, ], G) `

3 v$ t3 ]" i" {9 e

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-4-21 20:25 , Processed in 0.654423 second(s), 52 queries .

回顶部