QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

0 Q7 ~7 \) Y# R% X

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

; {' X1 j |# i% a- ?

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

9 u, c2 b% [, Z$ M- g/ X$ j4 G

一、判断目录是否存在:

$ D9 X6 D' f0 O

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

% X9 f' i b. s" g F& v

设char *Dir为带判断的目录7 r# c0 y( _7 d" J f+ \, z# {6 H bool Exist; // 最后结果,表示目录是否存在 ( G# Z4 I& Q2 z) X/ I/ rif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” 7 k1 ~ `9 O. J& F! SWIN32_FIND_DATA wfd; // 查找 % c( H0 O: j6 I& _: x2 `0 aHANDLE hFind=FindFirstFile(Dir,&wfd); ; x& b3 _% i6 Fif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 3 J& h1 W5 k& x+ T" ielse/ c0 z0 m" n7 B { # D( Q s; ]# G0 @5 l9 d2 ^ if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 6 M$ R; r3 O8 j" q) Y& ?7 H" b+ | Exist=true; // 是目录,目录存在0 ]8 ]8 j- F' V( C else # P. N% C J# C; R Exist=false; // 是目录,目录不存在3 z6 j2 D7 c. s4 B! F FindClose(hFind);% @0 f: W/ L S$ y }

2 a3 T% D! T# _5 d0 k r3 r

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

' c C% M E4 E$ ?4 x# f5 }

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

' E$ R; {; ^: X6 l

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle : `$ H! w$ ?, W( ILPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL ) M! k+ L W) `; jLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 & I: f" I7 s" Z+ r! l0 I1 f, XLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 ( w/ W v V; b UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS " Y. s8 p$ b% P, L BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL $ F3 B, p/ u5 O8 dLPARAM lParam; // 预定义的对话框传递给回调函数的值" K% z6 X: M9 I2 V0 \ int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 2 J' w1 l; W& ] 可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: T. s9 T& X! K3 z5 {, i' Z#include <shlobj.h> // 必须包含的头文件" U2 d) T' S3 b* S# b- S char SelectedDir[MAX_PATH]; // 最终结果 2 U' C+ J: m/ y9 J: sBROWSEINFO bi; // 入参; a) \4 f: _- P, B& |. i7 t6 V" x char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font 9 H! W- r- N! e5 bLPITEMIDLIST ItemID; // 所选目录的系统标志指针

9 |+ k, g3 q) [! X2 F4 n

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 ! X5 ]- u7 g4 c7 zmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 ) r9 p4 v) a0 q- ~1 Vbi.hwndOwner = Application->Handle;" F# s/ Q5 p. l/ l* b% |5 w$ N# P( B bi.pszDisplayName = FolderName;! j1 \# I$ B* {" |) A# s bi.lpszTitle = "请选择目录"; // 改成自己希望的; K0 ^# I8 d M- O7 Z+ n* x bi.ulFlags=BIF_RETURNONLYFSDIRS; 1 b5 x! e% {, ]1 P" X7 hItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 . N# b0 Z8 m E) K ~. Z" L" `+ o8 x3 Jif(ItemID) " i; a* l( d1 J& n* X3 n: X{ - r J: @0 U( c8 @7 A; l SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名$ A p, G1 P( X c GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 2 y- X9 x6 [3 e) {# a}

# f3 X( I7 \ \- F( N# F- j

三、直接建立多级目录:

5 F7 ?8 R; H. V1 g% l

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

( s. |2 u# [% S! i

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"% f. `' W7 c! j- e0 A/ h4 Z {+ v& W9 ]3 h: D4 x- \ if(P.IsEmpty())return false; 3 M% ?1 U) R+ P int len=P.Length(); - H0 K% Z4 c. z2 u# d char *Path=P.c_str(); + z9 n5 ~5 d( t! S* j5 G w3 S if(Path[len-1]=='\\')) ~) `5 J* F1 K0 x3 Y" {$ X" U7 l {. o2 w, j; h7 e+ |9 I; u3 L9 F len--;6 ^3 w2 X& Z5 o+ P" [3 @" f0 v Path[len]='\0';. i- ?9 l: L& @7 e( {4 i } // 删除末尾的"\" 2 _3 f3 l5 z! P AnsiString Dir=Path; M2 y2 W [# P // 分开父目录和本身目录名称 ; \! ^4 E2 r H8 A0 G; g5 t3 L AnsiString Parent;6 l2 K, J( F( k- H9 F for(int i=len-1;i>0;i--) : S( u. Y: C$ J5 ?( C2 E$ E {; v5 b1 Q' Y( Z6 L if(Dir.IsPathDelimiter(i))* b0 ~, @/ D6 g( D+ X+ {% G {2 [% h1 s$ I7 J- l; P4 }! B- b Parent=Dir.SubString(0,i);/ e. l' |9 ^" a break; ) g% M0 ^( J1 m: L$ Y6 P* D }( F9 B! O% w1 B* G. @/ O } 8 h) P5 C( l8 r% o) w5 m# Q if(Parent.IsEmpty())return false; // 目录名称错误6 g# r$ e9 B- z, ]& S bool Ret=true;# ` a/ h# H3 {4 C" } if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录* O0 t, I7 T" u r' c; P5 t Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在 & m; o# c6 a/ \& b; e) n/ V' S! \6 V5 h if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 6 c, F! G1 M- S if(Ret) // 父目录存在,直接创建目录) N% A7 d9 w/ G$ _ {7 `, d) b8 f% N7 B2 S) a) d SECURITY_ATTRIBUTES sa; , @, O8 k& m Y sa.nLength=sizeof(SECURITY_ATTRIBUTES);$ U0 a7 \ O6 h1 Z* m& [' W sa.lpSecurityDescriptor=NULL;4 N' H1 q8 s: t% v5 k4 D sa.bInheritHandle=0;; |) @9 N4 ^. h2 ~$ _3 R0 p' y Ret=CreateDirectory(Path,&sa); 8 k, Q" }9 z/ A4 s0 E8 J7 X" c } % T: `- G7 E; m) g( S0 n2 k4 M- w return Ret; 1 L' P( T6 y" J- I} : T1 j9 g2 D- \9 r, @- V, r4 E 可以看出基本方法是: 9 O* O8 ?5 n: ]4 M先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; e/ n* g0 s8 d; c+ U* b如果父目录存在,则直接创建目录,否则自我调用创建父目录。

/ J8 [3 w# q9 o2 A5 }+ ]

: Y) K% K+ o$ E+ v- S0 L 四、直接删除整个目录:

/ {- h @! O8 d/ k' o+ q! k

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

5 }3 p& z# t( J; G/ o

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 4 z3 I! F. i) v) k7 {6 Q 如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 ( F* H8 d/ y$ Y' r: n N 如果找到目录,则进行自我调用,即开始递归过程。 ) l/ V: o" f, M. P; r/ @% d4 _ 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 - Q" t/ j- K! X5 U 具体程序代码如下:

2 n5 @' O+ R |# {0 k; k

bool DeleteDirectoryEx(const AnsiString &). D9 ?$ C/ x7 C) a5 J# y5 q {8 a9 d# h6 T% k2 [# |2 d if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 - D w: `" [" ]- ` int len=P.Length();- L H* O l2 F8 D m B% @ char *Path=P.c_str(); , {0 F0 u: e+ q# m. P AnsiString Dir=Path;# g5 N. Y& s( g7 E0 U if(Path[len-1]!='\\')Dir=Dir+'\\';: h H$ ~5 F8 j% Y7 Y$ N. |, h5 u2 R f AnsiString Files=Dir+"*.*";6 \) {% \. C# K. f# O V+ c WIN32_FIND_DATA wfd; 0 x5 T H I. t HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); [' z" S# o2 A. I' q$ q( E bool Ret=true;) j' a8 {/ T( i/ U/ J AnsiString Tmp;2 Q9 ]$ M7 E% x" g if(hFind!=INVALID_HANDLE_VALUE) * v- [( u* M$ q {7 ^, w u# N4 ~ bool bFind=true;, ` P: t8 L6 X+ m8 N3 y! g6 v while(bFind) ' p+ I% M! h4 l% a" {6 ? { . u' X9 H6 ]- a" w, ` if(wfd.cFileName[0]!='.') // . ..- \$ ?" u% o0 U3 h$ I# u {6 a# o2 [& J) Q0 ] Tmp=Dir+wfd.cFileName;2 D* C; f/ b( q* {! l if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)4 [5 B* P: b `6 O& x7 l+ g& r { // 删除所有子目录 9 p1 e& q$ [; Q5 b2 _ Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);, M# K0 A8 w* [! y3 g }else4 Z, S+ l# P) n# Z( D9 J0 N6 k( m { // 删除所有文件 . J+ g2 Q' Z% V$ a7 @ SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); ! N; o# X) w6 [, j0 S7 Q, ^ Ret=Ret&&DeleteFile(Tmp.c_str());& u+ ?6 k. V/ G# ]& j* |/ s+ s9 X }) J5 D1 V/ L5 E; l" @) M* [# j }/ j9 t) c" `+ ^: B. ]; H bFind=FindNextFile(hFind,&wfd); 0 w; N3 n* u0 z8 w" j7 o4 i }0 \, c- o/ w% @$ O3 S FindClose(hFind); 6 c. v1 r, Y6 e2 e2 G } / A0 @ @& E5 z! t8 E if(Ret)return RemoveDirectory(Path); $ F8 r$ W; l6 U @ E. ?& T return false; 4 v: _' y; {: x2 Y5 C* k) `} : @' a6 L) r1 x( t9 ]8 u7 I; U

' T% r* `) q* S x3 W% [

) H8 \ \- k% a( n

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-11-8 05:39 , Processed in 0.551289 second(s), 51 queries .

回顶部