QQ登录

只需要一步,快速开始

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

目录处理函数

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

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

目录处理函数

' {) f! x+ O9 s3 W

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

. Q, {6 c+ {! B# n- r4 o" }

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

& l; ]7 _' K( ^2 w( [0 K2 Y7 B: l

一、判断目录是否存在:

) K- o' `2 x0 ~! B' L

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

0 F8 T* _3 f0 @. y9 R" R; A

设char *Dir为带判断的目录 3 v$ d; i0 J1 Z; } d; K1 Obool Exist; // 最后结果,表示目录是否存在 # [' j% y+ Y1 k! r d% zif(Dir[strlen(Dir)]=='\\')Dir[strlen(Dir)-1]='\0'; // 先删除最后的“\” / k8 a0 q2 e7 d9 ~: T) J1 NWIN32_FIND_DATA wfd; // 查找 , l+ v6 J6 N. z$ ~HANDLE hFind=FindFirstFile(Dir,&wfd); $ i+ P. B% _8 m! K+ o: uif(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在: \3 x" f7 P* b) N- J else ( }( r/ S! |3 ?/ G5 n6 ?: `( S% \{ + G% m: O8 N" z/ h! e4 j if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录 + B9 n5 h" ~* a Exist=true; // 是目录,目录存在& V$ E+ \5 @! B# `6 ^# i1 Q0 e else ' n/ z0 @ @! z V. l0 m: J Exist=false; // 是目录,目录不存在& f/ r- U" N/ X3 J5 ?1 M FindClose(hFind);, o! F/ S( k* ]5 G: f! z }

' J: u; Z, D1 n: V0 F# u" R

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

# R7 @. M7 D# L0 y

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

; I8 G3 Q0 q- S6 D2 h) c

HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle 7 _7 ]* l2 N' r) z* M( Q4 C LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL + ~7 T7 u* I% ^8 lLPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置 % H; g! V$ y3 L7 f2 j$ @4 B7 G* Z LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置 ' n5 }/ D0 P0 [8 G3 TUINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS , {" T$ v) s; p) F! i& xBFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL 3 ~' a; a- R3 J% l LPARAM lParam; // 预定义的对话框传递给回调函数的值 + q- ]9 ^! r& Sint iImage; // 与所选目录相关联的图标在系统图标集合中的索引 3 C4 X! Z9 C' _- | ?- x) s可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下: : u1 @4 o9 @3 Z! b _* [! F' D #include <shlobj.h> // 必须包含的头文件0 n& r' M3 {9 a4 `/ n- | char SelectedDir[MAX_PATH]; // 最终结果2 c G1 U3 Y" K! R9 x) M& { BROWSEINFO bi; // 入参 / J. I$ { Z+ n3 i& e' Gchar FolderName[MAX_PATH]; // 所选目录名称,例如选择C:\Windows\Font,则为Font : ]$ d S) }# J, a, PLPITEMIDLIST ItemID; // 所选目录的系统标志指针

$ ^0 b, N# ]; X& G) C" G

memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果4 U& i3 d* x I6 R8 a9 B memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据 1 ?8 `; |& B6 D; q/ J3 Lbi.hwndOwner = Application->Handle; 8 G+ d- r. R% T- xbi.pszDisplayName = FolderName;: M, O* P1 i6 C( d. m+ E0 q bi.lpszTitle = "请选择目录"; // 改成自己希望的 * J8 A" m( Q& z' `bi.ulFlags=BIF_RETURNONLYFSDIRS;1 m5 K) M1 L! y' [& X- G8 L+ l ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框 & m+ e' {' t0 V' g, J Pif(ItemID) 8 U+ ]0 d. N j- X3 o9 H{ , I/ a7 ]- G; a' q9 B SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名 ; }( l& {9 L# c0 R: |$ _9 R5 G GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放 ' R$ C+ n& W2 ~' i% J2 z}

% {2 }+ x$ K4 e6 g* V2 B

三、直接建立多级目录:

- a& c" X a$ {

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

' E% u/ K; u* z# E) Z

bool MakeDirectoryEx(const AnsiString &) // 入参为打算创建的目录名,根据操作结果返回"true"或"false" $ y7 s8 S# [$ T0 z9 x! k{4 s/ _3 u6 e; { if(P.IsEmpty())return false; 4 O! J* b. x; Y" g9 H5 Q0 G9 [: T4 y int len=P.Length();5 w s/ C7 E; b; t9 I char *Path=P.c_str(); : a* y! E6 L8 A3 ^% }2 F! J5 g1 ] if(Path[len-1]=='\\') 3 a5 n2 ?# _, G' M { , m3 I" s: Y5 |/ }' D3 {! w len--; 6 Y' g1 Y/ G# Q1 |: N6 Q Path[len]='\0';. g( h4 @/ q/ u6 Q+ w } // 删除末尾的"\" - B: t9 h- P# @- q AnsiString Dir=Path;) a/ b* [4 M5 k v/ k // 分开父目录和本身目录名称 K' T# P5 s8 v8 z+ ?; X6 v AnsiString Parent;. i& A! `9 Q7 S! ]7 v6 P9 A+ n ?3 W for(int i=len-1;i>0;i--)% u& O8 b& K* T9 P& {, C5 X( U {3 O" N l! B' J- { if(Dir.IsPathDelimiter(i))9 \% K* u- l+ P$ c" f { 7 q% o. W9 i0 Q- _1 g( a9 N8 w" m Parent=Dir.SubString(0,i);$ A# F/ T' |3 d7 j F9 j, k% L, l# U break; 5 T1 K6 W1 _; v/ p- U } 0 s% z$ b3 B6 q x: v8 a }2 Y9 |& k7 { D8 [ if(Parent.IsEmpty())return false; // 目录名称错误 - t B0 K5 r7 x' J# `- A* O bool Ret=true;) q# w0 T: S2 r if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录- P8 G. E; T5 u& G. i6 l/ _ Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在9 x; v* A) P* f: F* O: q' x if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录 1 X& m) ^" `* Q) ]: L if(Ret) // 父目录存在,直接创建目录 1 o" C! b5 J2 ^3 G' b { ! M. h: E; l R$ Z" @ SECURITY_ATTRIBUTES sa;- [+ A+ @: d/ n; S sa.nLength=sizeof(SECURITY_ATTRIBUTES);4 L% Q! j- |, b, D& Q+ L* z7 d @ sa.lpSecurityDescriptor=NULL; 5 b5 I9 \0 o/ T! l sa.bInheritHandle=0; 6 G# q5 n: P. t3 W* M# O Ret=CreateDirectory(Path,&sa);! E2 ?* s, b. f9 p3 k+ K5 t! d( Z }6 |# D) J t) t0 [5 G8 N9 [ return Ret; 0 [0 g2 q+ T' v$ w& E. ~" _5 I} 8 Y) f' m/ I/ U2 e1 ^+ ~ 可以看出基本方法是: $ T# q: N c/ }% d) y: U先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计; 1 M& ^1 O) [$ y. W: A如果父目录存在,则直接创建目录,否则自我调用创建父目录。

2 y& I, L. E' [; }7 U

' F' F) e# [5 \4 Y$ v) X) i四、直接删除整个目录:

1 J9 ^8 w ]! |% G4 b0 X

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

/ b) s- V) F n; J6 f

查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*) & |9 h- Z( O( w4 t) ?% L) U如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。 9 E- u. l- n( i$ A如果找到目录,则进行自我调用,即开始递归过程。 " s+ f8 b( D% j+ }- |' h如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。 l+ H8 X1 W m0 s0 a1 o+ E 具体程序代码如下:

7 ` @6 s5 \+ g1 O* t. V) k* [, V+ b' K

bool DeleteDirectoryEx(const AnsiString &) 8 [" O- P0 }4 E/ G5 n+ m$ j9 |/ K{8 @5 {! b8 a* W) {8 {8 j* V if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白% V c( l) ]9 a! }5 ?5 L0 u0 x2 M int len=P.Length();6 r% P* S4 E; W char *Path=P.c_str(); 9 ~0 Q* K4 y9 A% d& n0 [ AnsiString Dir=Path; * D2 O7 r3 w. B. e2 {8 K if(Path[len-1]!='\\')Dir=Dir+'\\';& j) K2 R5 t* S# N! `2 L AnsiString Files=Dir+"*.*";. H3 E+ o6 t% S$ N3 B/ w2 L& a WIN32_FIND_DATA wfd; / a. \) j! P' P/ U4 A HANDLE hFind=FindFirstFile(Files.c_str(),&wfd); 5 [3 F" A# X: W; `$ Z& |9 \ bool Ret=true; 7 s* G. f, U$ g8 }0 i AnsiString Tmp; 5 T1 \+ N5 H' }, [) \ if(hFind!=INVALID_HANDLE_VALUE) 1 B) b7 Y9 g; N$ E$ z$ n3 v {! F' P+ n& e2 K8 B* K& A1 b bool bFind=true; * T5 M, B O" z. I& C* Z" ^ while(bFind)7 M8 C; Q8 D: z( t8 I2 E { ; e2 Z( f( q1 w4 h if(wfd.cFileName[0]!='.') // . ..2 x5 y$ t. i, r$ v { $ S0 h" A$ c5 }; y t8 H Tmp=Dir+wfd.cFileName;( U* L8 Y( d9 f- G4 V if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)& Q* |3 {' g" i6 J! t `; y { // 删除所有子目录0 m$ R" Z& _5 M0 Z+ N6 N8 Z Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false); - I% ]1 D: K b5 z }else) G4 O8 `- m' V3 u+ _ { // 删除所有文件- a, w+ R0 @# t* H( R( e SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL); 3 i9 D( W0 z) F4 `' x Ret=Ret&&DeleteFile(Tmp.c_str()); 9 z R. D2 b* d" m, ]; [+ \ } * |5 C2 l o6 X$ O! @ } / [2 f* u2 D6 p! |! f- O6 o/ N9 \ bFind=FindNextFile(hFind,&wfd);+ Q O3 N& \; ? }& j% \0 W5 d5 d FindClose(hFind);; l* _5 L2 x( ~( N* Q' ^5 Q }7 i3 a3 }4 N, Y! R& U1 a if(Ret)return RemoveDirectory(Path); V: Q/ _8 h4 g, P7 d+ G6 E% Z return false; ) z; W$ o/ s( c: C) W} . x3 U! ~5 {9 J7 H7 f8 @( Y& V& C

( w3 |/ a4 a/ F5 K$ S! ~

) P0 j: `* C3 m& }' t# N- I* M. j

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-20 06:01 , Processed in 0.441329 second(s), 51 queries .

回顶部