QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

1 Z" ^, X; n% U n/ p

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

, O, `- A) O( u/ r4 o$ m' b

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

3 G# X8 ?: O9 `

一、判断目录是否存在:

) l8 K& a5 L& w1 D, m: _* j

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

" X! m0 f) L1 v0 W6 J1 D% x3 U3 U6 P0 Y

设char *Dir为带判断的目录 5 i( M; {( Z# B9 obool Exist; // 最后结果,表示目录是否存在 . a, ~$ ^7 F, } s* v4 S' Q8 q' t$ rif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\”; e, u# H3 {; e7 ^8 R WIN32_FIND_DATA wfd; // 查找 $ ~8 q8 V: C% i1 G2 pHANDLE hFind=FindFirstFile(Dir,&wfd); 7 y( E7 g9 N5 K if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在 & I& t+ I3 m; _) yelse 6 ?/ N! @& v9 ^6 `; b% E/ P) T{ * T, `3 B l8 B; c% _1 B/ ?+ h; k( | if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录/ }, q" L2 n) u* h, a5 f Exist=true; // 是目录,目录存在) q% |4 K, r$ E" F5 m else1 C) Q& W9 c( W4 g Exist=false; // 是目录,目录不存在3 |: L7 N5 q* O! T( r3 X- ] W+ u) u FindClose(hFind); 6 P) \5 X* U2 Q5 q" S* T) x1 ?2 o}

) T5 }) A5 u, ~* P1 x; g2 b

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

) V/ d' L( l# D' m% O1 c K

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

0 m) ^# E2 m( X3 z& c

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 5 i+ z2 g; g& o- a D: \: q; H LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL; F/ [3 ~% w/ X$ p- @. c LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 4 n; S7 Z* G7 R8 A1 Z, GLPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 6 ^1 n) ]7 l9 b$ i7 m3 u4 KUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS % d6 t1 q" }! I. s* L _BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL , S0 G/ o( J8 ^# Z0 K LPARAM lParam; // 预定义的对话框传递给回调函数的值$ j! O) I8 O2 V6 @" | int iImage; // 与所选目录相关联的图标在系统图标集合中的索引 " F( c# d. k6 k/ r可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: 6 E. o, _% @1 a: k& q0 D9 u#include <shlobj.h> // 必须包含的头文件# n0 w7 Q6 `; m" q9 [ char SelectedDir[MAX_PATH]; // 最终结果 0 Z+ n. D# o) D1 U$ ~" P3 IBROWSEINFO bi; // 入参 Z$ H0 ~$ i: M" g0 D6 H char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font + c$ H1 g1 s: C9 G( r- qLPITEMIDLIST ItemID; // 所选目录的系统标志指针

$ o9 o, e! l. z

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果 * N. M4 ~1 {: q4 N& W2 h3 Zmemset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据; a- ` Q6 `- c! d, t0 I bi.hwndOwner = Application->Handle; 6 r* e7 W9 P# G' f8 T7 jbi.pszDisplayName = FolderName; * Z+ l3 s( s* T- kbi.lpszTitle = "请选择目录"; // 改成自己希望的# k) U( B' b( M% ]+ U bi.ulFlags=BIF_RETURNONLYFSDIRS;) F+ E; a$ D' Y ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 , U+ l4 b& a6 D' x, H/ t& u' r" ~if(ItemID) & @. q3 t: r l/ N2 L9 z5 ]{ & r9 {6 o# Q8 `+ l SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 5 H8 G% Q3 c$ n& B2 ?# m$ F GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 ' r/ G* Z! J5 ]8 G% @4 B; k/ p}

3 B& x! P: F. Y' T% A6 a& S( v

三、直接建立多级目录:

/ {" r- X K% L; u3 @$ h' o

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

3 n4 t3 A* C& G3 r/ Y

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" - E/ p1 @6 \) q ]( V{ . z2 [; U2 m+ O6 A if(P.IsEmpty())return false; 8 Q2 l( Z' d8 h( L; m int len=P.Length(); , s- \0 d6 d+ d* z" v char *Path=P.c_str(); ; p' ~4 H' m) m2 y3 a if(Path[len-1]=='\\') 0 d7 s- O' E1 a3 {# L6 m" w { , k& `) x0 Q# B5 E; D+ r7 R6 A len--;4 _; Q i! O( G1 M Path[len]='\0'; / R* h/ V# S3 T } // 删除末尾的"\"5 o6 C- n o3 [6 [ AnsiString Dir=Path; : J" |9 N8 R- _$ z2 x4 A7 \ // 分开父目录和本身目录名称 3 L6 c% w$ c" A. w AnsiString Parent; t6 L+ D& ]/ D ]0 h# W for(int i=len-1;i>0;i--)0 D' ^, k1 S. \( ~$ z {- ^/ U9 B; C! w4 \: m+ V if(Dir.IsPathDelimiter(i)) ( Q/ e5 ~2 o2 t! P! V( W( U$ f { - ?2 }( c0 f8 u" U Parent=Dir.SubString(0,i); 7 \9 T1 q; a' K6 T break; & f. u# q! I3 ?+ n3 Q8 [2 Q9 y }5 J# w0 ]( h+ g# G+ K) P% _ }( V" e; r5 d. D$ U+ S' F: x; G0 ? if(Parent.IsEmpty())return false; // 目录名称错误 : w, n# E' B4 L# ^; l# X: b! C bool Ret=true;/ _6 Y& j1 U% b1 {' h" }! A" @' l- X if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录 % i4 D$ g9 _- P2 h+ j) u% I Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在6 X. O0 E: z! G5 q* M if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 N L2 S/ `* ^/ }( G) v/ k% _, m0 [ if(Ret) // 父目录存在,直接创建目录 % _4 x; Q, q% g { % Y/ h# H j; j1 d* v* J SECURITY_ATTRIBUTES sa;% Q1 C6 r: Z! G* V; E) v$ S% ]8 k sa.nLength=sizeof(SECURITY_ATTRIBUTES);2 X! {5 J, C V4 g2 o5 u* P1 L sa.lpSecurityDescriptor=NULL; $ U4 W' I6 u6 \) n sa.bInheritHandle=0;5 ` @# \ {& q* j4 s! Q$ H8 F Ret=CreateDirectory(Path,&sa); 8 S. F. ^) n5 \# w- Y( l! F }% ]6 R* s+ a- P9 m3 [ return Ret; + W3 _4 X2 F& J: K! {} ' N5 f/ ~# B( f5 L4 Q0 J' Y 可以看出基本方法是: 2 l! n& p8 ]- |; }8 d先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; ; P" B+ X# z& P' A* j( _如果父目录存在,则直接创建目录,否则自我调用创建父目录。

5 Z- P0 C% o# K M# i

/ ~& X1 L; ~6 B0 }" X# M 四、直接删除整个目录:

, ?1 U0 `: B: U- o5 L7 }/ c% G( @

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

W, _( k: ^5 o6 M; {0 E7 A

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) 7 V/ F1 `0 _$ _; C如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 : ~4 p; k# x2 [; i, L 如果找到目录,则进行自我调用,即开始递归过程。 , n+ x* k( W. |" t D( c 如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 ! Y H+ b, J3 ?1 d& G" c具体程序代码如下:

4 t( k3 d/ f- h+ b6 q

bool DeleteDirectoryEx(const AnsiString &)4 X# g/ ~( K. b. i/ I) D {, t- D" u2 D% c* z8 z w' p$ z if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白 / m5 |9 y- a7 K) C int len=P.Length(); - l8 P+ U- S8 m- t/ Z1 e, ?- ] char *Path=P.c_str();. }# ?7 E. [: ~7 ] AnsiString Dir=Path; ( v! S( F' G4 S1 B if(Path[len-1]!='\\')Dir=Dir+'\\';" E$ O# e* X' |! G AnsiString Files=Dir+"*.*";: p' s5 E" b! Q/ p- W% K WIN32_FIND_DATA wfd; 2 J3 r- ~2 r2 `' V% ~$ S, H HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);+ V$ H0 I) F& n9 ` bool Ret=true; 5 v; K7 x5 v6 m3 C4 u AnsiString Tmp; : _; K! C7 I$ J4 V! Q if(hFind!=INVALID_HANDLE_VALUE) % I: |6 F7 A: _8 r# @- { { 2 y: r0 ?8 x& }3 [6 c bool bFind=true;/ T) |, C4 q- _) S while(bFind)- K& E0 `8 I8 E m/ A/ I& A { # k' C2 x3 @/ N1 E. R2 W if(wfd.cFileName[0]!='.') // . ..- x- v) Y4 L- x) Q L {, G$ N+ S# m3 @9 Y0 W- w( n Tmp=Dir+wfd.cFileName; ; @ N2 _2 m' X$ s6 e if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) Q, I, S, g4 { { // 删除所有子目录! ~2 b9 r! K9 @$ B1 w% F/ ` Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);5 J: H% I" T1 Q/ e$ |( D }else ' H6 l" K" }6 P" ?7 ?! G6 z { // 删除所有文件& K" G9 |7 _5 Q. Y SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);5 l; g( k! I A: c0 f2 K Ret=Ret&&DeleteFile(Tmp.c_str());4 Y7 s8 i+ S! a2 c }( N S' B) f r+ a } 7 x- o8 u1 I, x: X; j5 y bFind=FindNextFile(hFind,&wfd);0 P7 W, u' V) u7 v( y! T0 U) C } 1 c5 F0 s4 d) Z+ M: _% _ FindClose(hFind);$ z! n: o: m. `9 D$ v } T. {7 o7 x' Z9 t n, [7 n4 O if(Ret)return RemoveDirectory(Path);; N% o' v( L# [7 P return false;" a, E3 E, x% P& z } ) }( L7 T& m t; }9 d7 f; o6 W+ s

, [# z+ M. r+ V+ H/ p8 @

: P, X% y% V# b8 S5 }: i' n: h N, q

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 13:26 , Processed in 0.403133 second(s), 51 queries .

回顶部