|
2 b- U/ y* B' w! P! }
湖北工学院图书馆计算机室 $ ?2 s: w& r' P# Z8 @$ B( r, n
张明武 $ m S' Y) ?, g' A
4 Q! t% g5 ^/ ?6 C" |. ?; u2 C---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 1 C. h2 n* S. M3 J/ x
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE & J$ x* C B2 U( x6 p$ C
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
; O$ Q' V/ ^( A2 E9 t' x区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 " v9 S) C r2 X( u9 C/ e6 x! I I
库进行备份,很难达到最佳效果。 & O8 ~3 ]8 e& ]( i' B ^+ k
! P3 K4 [3 ~3 y V) a
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
2 k$ V' m" }0 K& w; D, D现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 2 f, u2 D9 C- g3 Z6 f. U( i2 U
可以直接对一个目录或目录树进行操作。
3 b' m/ P) z8 w B) E; }6 ^% _ 1 O! i O |- {' d. F4 G
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
1 d8 x/ x: {8 t) Y8 d文件的拷贝操作。 $ o% |5 ^2 h) h2 L. g1 i8 C. k
2 n E0 H- B! ~1 z0 h; C一、 原理与结构 . @9 e0 e, v0 T' V. r# q
: c. }$ A/ F/ ^- A
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 * f: x) A0 ~+ w. I3 ^& g, L
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
3 l& N# C1 X$ Z$ z% u
( @- e, v; ~: Y---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT 9 K+ Y* l8 J! R
lpFIleOp); ) E& r, c: @+ L0 G" N
# Z w( Y0 V+ g g1 x$ F; z---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 $ H5 H- g4 e; O- _4 U4 T
下: ! O/ l+ e4 @9 D; g
' U2 Q: f1 r+ P! y" \
Typedef struct _ShFILEOPSTRUCT {
6 F; h+ w3 I7 ~. y ~1 \- \/ u3 z2 I. b
HWND hWnd; //消息窗口
/ s; O1 k3 l9 g0 m/ t }" n ! ?9 b M8 Q) u
UINT wFunc; //操作类型 8 k% j3 r; F* k2 o0 Q
4 F/ B% K2 j) `1 d" D4 }7 V LPCSTR pFrom; //源文件及路径
% l! ^8 K3 a1 S( }+ m ' c5 _: s- p& D' s, w2 g
LPCSTR pTo; //目标文件及路径 ) q* ~3 A' X l+ O) A
, a6 U! a* a; {0 ^& L2 [
FILEOP_FLAGS fFlags; //操作与确认标志
8 I7 K9 L- ~5 ?/ v* H0 r 7 S8 J: P+ v6 o0 B/ `: U
BOOL fAnyOperationsAborted; //操作选择位 + r6 ]' U9 q6 V) i* e2 {5 G
4 d3 {7 s; F& ]7 ~& t8 @4 a3 n LPVOID hNameMappings; //文件映射
- N, T: ?$ c9 }/ y" w6 K
- [' y, J7 T9 q LPCSTR lpszProgressTitle; //进度窗口标题
/ Q7 X5 ]# [& N* E" [7 {, z' B
8 s' _! W a0 u8 {; b" ~& Z ' O6 T* Y9 k& q6 s e+ |
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
9 c V1 I4 A0 t/ N
& `8 R/ T- O' c( D$ n
0 V0 S1 m H$ j/ D; i( O, W. y5 x I ---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
. g" z* ?9 x; q7 F与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 3 _, m( O: h$ Q" q7 p+ |
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 4 x8 d" W! ~ p {0 t o
个,则应是:
6 @6 u' t$ q+ C! M+ o6 _ " W2 h& O: L7 U m8 D- B) i
char pFrom[]="c:\\windows\\command
0 m! i" [, O& h+ E" C) k+ [/ p# B 8 v; b) G% X0 ?& M
\0c:\\dos\\himem.sys\0"
; [. O- F3 E: i1 R" r& O
. `2 a; i5 `+ Q% |% D( W4 {---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
1 o0 f- {. s+ ?6 r, e进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 / M% H/ F# s; Q8 S' g( l3 T
要成员,它指出将要进行的操作类型,是下面的操作类型之一:
7 I0 B3 I' F; a " y: D- d) ]! a4 {1 [0 `. U
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 ; C2 e- B- Z0 o# e
+ R' a% \6 H- ~4 q9 ]9 A" Y
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 ' \. c: u& m- E
8 ?2 f$ W; {: C: | w% B" K9 v
; Z0 H/ H0 X8 y7 P ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 ) ]- J2 ?; @3 X! B
$ `5 e: o$ J; I T
---- FO_DELETE: 删除pFrom指定的文件。
. D8 [5 \: X2 ~, n# @
& c' \) `, y C---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
6 S) ~' H8 b0 z3 {程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 3 f- Y9 p# H" ]# ]# T% ~) B
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 / _1 o0 I: C1 S# y) ?( t
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 - W4 {: X' z, z+ V( ?
组合。 1 N4 o8 ]2 {9 A9 n1 R) z- E
) j3 @. M* u$ G' P0 a% z; E ---- FOF_FILESONLY:不执行通配符,只执行文件.
3 c d- _9 z3 H 3 s0 M/ j% b l F: N
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. # {# \8 j8 L9 D P0 N6 w) t( I
% ? k0 d N. Y$ v6 b9 i ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
; }! J* v5 K: g( Z6 B: t3 j候,如 & K2 }1 J: N( `) L
果不设置此项,则它会出现确认是否覆盖的对话框,设置 , v i Z/ x' O. f% a& @
此项则
! \& s+ J3 ~* q 自动确认,进行覆盖,不出现对话框。
O9 Q4 x1 Q# y$ F8 ~7 u
( x3 w6 \% I. H! q ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
0 d2 b% v0 Y' S% z6 p E7 d j现错误
8 Z9 q. x& E! B. e* G/ i! r" ]( v3 U& _ 时,不出现错误提示,否则会进行错误提示。
: G- L9 x) D& d
) v. a4 `0 U7 M k# I. q! E ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 " r# g$ D1 p$ c7 P6 r7 S
进行更
: A2 f8 `! m; K, W 换文件名提示。
8 C. X# C% p- K: T
/ W; R8 F- ~; j, G3 A [ ---- FOF_SILENT: 不显示进度对话框。 6 y8 N; G* f7 ]
, O: ^) \* e$ |8 N
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
7 ?9 N, n) P, g# I( U( ^函数返 / E. C/ V5 t. T* p0 ]
回正处于操作状态的实际文件列表,文件列表名柄保存在
7 o) ^* @- @* D, c1 x! B
% z; c* Y6 \. [" L4 r hNameMappings成员中。SHFILEOPSTRUCT将包含一个
: X2 u- H' ^) w$ [& E) w SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 4 Y. N" `8 O9 x: \: n
个处于
( u+ p+ b/ m8 i! q 操作状态的文件的新旧路径。 2 N5 e# e0 ?% A
, D0 \8 _8 \9 g
二、 实例操作
, |7 m# c1 q$ d5 I+ l8 r* C
; Z; n" @: r4 A- g5 w---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 $ D( g" b, Y- X- |6 s% U
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
8 h3 u/ U- e" A5 {- k2 c2 p% B: F工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. . c. k3 D: o1 ~2 r3 Z$ C" `
cpp的OnCreate()成员函数中加入工具栏。 * x$ E; m+ A0 q3 e4 V
7 z. p; l0 Q0 j' J
if(!m_wndMyToolBar.Create(this)|| * ?* [3 [# w0 H4 C3 M
+ E3 M4 A3 [% c v) J3 ? !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) 7 _ W2 d/ \6 L/ v
) n9 U. N5 ]7 l5 t% w% | {
- e) v/ u- a2 s8 V1 G2 `
, D7 P w1 `& }$ l3 I* i5 n TRACE("can not create the FileToolBar!\n");
6 ~/ Q5 d$ N3 m: y4 ]( ~+ ~; h , u- B ]! W" ?7 Z/ H
7 r7 G$ _% P2 Z8 E return -1;
: C, Y/ K& }: H$ B h, C1 D ! c- j% C0 }4 }. f& K, X
} 1 `* H! {0 ]' u6 C2 ^: d% A7 p& y
! M! U: y5 O' y' ?3 X
! D1 h! A! X6 [! V---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息 5 o7 V& M6 ~/ o) m$ m# B' z0 i) H
ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 : o7 S+ Z; M; ~2 Z4 j5 P
9 G; _8 I3 F+ U- p void OnFilecopy() 6 R( i5 g, `, e U* Y# j
{ % x" {! {3 h/ Z! v% l6 S; g' t4 o
int nOk;
! m$ S M6 y* X8 }% q4 J! b6 J2 x char strSrc[]="c:\\dos\0c:
; f/ A Y9 _+ m2 y" M\\pwin98\\command\0"; 4 O! m0 E! h' a$ b E' T
//可以改变源路径
7 D, D" n! `# u l2 C0 l, C ) A9 S/ C. Z: E! r; a
char strDst[]="c:\\temp\0"; 8 h1 r8 F. E2 }" k+ L8 y4 q
//设置目的路径
: l/ E* E9 @% }: d 6 R: K+ ` J: ?) E/ T/ h
char strTitle[]="File copying";
1 ~5 L- j/ D- E0 _% } //进度题头 ! X$ u y3 V* t+ H! G& P
5 v5 V E) \0 l% D: G/ G* z* l3 ~. Q SHFILEOPSTRUCT FileOp;
; Y4 v4 t, G M6 E1 O
% y5 W( e3 `" B# p! k9 G FileOp.hwnd=m_hWnd;
! M% E. u& ? ]
) J2 i0 G6 i( J. k7 w' O5 z FileOp.wFunc=FO_COPY;
* u8 h0 X( t! [2 n. w5 y8 B, Y 6 p/ Q' ^$ T) m0 x
//执行文件拷贝 % {) P: z7 q7 C. Q
6 }- J3 P) U" e7 `9 V8 G' K; O
FileOp.pFrom=strSrc;
+ _8 N9 A. E; O! U/ X9 k
4 c% P+ v5 ~' `* C& p: N$ J FileOp.pTo=strDst;
/ D* p$ v+ d: X2 X" G+ m' S3 M
6 X, k+ O4 h/ @8 a FileOp.fFlags=FOF_ALLOWUNDO;
8 ?) a- f5 _$ B3 t( \8 J4 X; J2 c
" n9 |& O9 N ~8 Y( `- w2 l* {1 n/ T FileOp.hNameMappings=NULL;
) @& V( \. X7 w' [' L. R 4 Q$ Z) u0 h, [1 {8 Z
FileOp.lpszProgressTitle=strTitle; 9 z% p5 w9 B2 Z9 z. Q( B$ F0 J' l
6 k9 u7 |/ S: J. b G/ r nOk=SHFileOperation(&FileOp);
4 y- I3 T+ g( i" l* S7 e & }' Y" ]/ W/ p$ a( J
if(nOk)
1 m2 B; e, J9 w+ t" ^
6 O- S0 b. }6 T% ]' C& C' h TRACE("There is an error: %d\n",nOk); 7 t' l3 t- q2 \, |/ |% I, W
3 j5 }- @$ | z9 u/ I0 j else " B" n/ w( J/ i6 E: N3 Y
. z6 A: H1 M. N+ h% H) M/ v TRACE("SHFileOperation finished * I+ z: _' o. h2 ?, F' }3 D
successfully\n");
5 H. Q# [) T- [. j( e/ V % c8 d/ Z' v1 D0 j. g. X2 N5 B5 X( i1 e
if(FileOp.fAnyOperationsAborted) 0 O) z$ c% B1 C' T+ b3 v+ g
5 X4 U+ u6 W w$ G
TRACE("Operation was aborted!\n"); ; g' h& G: R a/ \/ Z
} 3 {) e# z% E, [% |: n! I q
6 ^% q! ]5 G! `+ M5 k2 u
I4 q, C$ T" z, x% V4 g三、 结束语 " N# v- X* o0 h' J. k
/ @' X# I& W; P; t; j---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
$ N3 w7 D5 Z* R: q2 E' J的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 * _& R! v9 m! L$ {) ^+ i
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 ( _9 A/ W7 ~& O6 P/ ^
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
$ J3 j4 K' J% v3 z; z# @ $ l$ m i9 e" N8 G/ q8 h3 Z# }
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
6 y) A- H" H6 R6 \到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
) F1 P4 \( f: h( n% L3 }3 ^' b地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |