|
9 e7 y6 C" g% W& h4 {$ e3 z湖北工学院图书馆计算机室 + @9 D' a" w0 p) M+ @
张明武
7 S, n, D% N- z" N* q! b1 |8 P
6 `4 ]! m- |, D. ]+ C3 D---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
/ o3 F- X, T$ A5 ?3 X2 p% Q/ d" B操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE * M2 e; r9 L6 W2 W) E S6 C
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
# r a2 G: c+ v区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
! H2 V# T; T) L' L库进行备份,很难达到最佳效果。 + u' P% a- x) O
' S3 G9 o0 x3 W5 R! N
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
+ c. ?1 k' A$ A0 v2 O* o$ C现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
8 B7 Z! w9 X6 J3 X# i可以直接对一个目录或目录树进行操作。
3 x# B) z0 u' \" b5 ] O. o
" C, V* q# h/ Y---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
* l& q( o: p" O1 ]% y文件的拷贝操作。
6 [" A5 s' }; R: G
7 z8 S% W6 Y- |* V8 C一、 原理与结构 7 N& y$ S% G0 c
. i$ L0 D* g6 m+ F! N
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 0 O$ w: y& y6 c" b
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
# L; x0 R. W$ V' C, k/ k7 z6 X 7 W g; |3 D9 |5 M8 I
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
4 x/ Z; N# j" O1 I. VlpFIleOp);
# E- n4 h+ G% H
& K3 B# T8 d6 u0 C- r: n; r4 ~---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
% q* Y- j7 U S( _: `" y, n! {下: $ u! C/ C/ |, x
# n3 _+ r0 U! Q2 O5 w$ C. I Typedef struct _ShFILEOPSTRUCT {
1 F5 o, Z7 g/ M% q1 @( J/ A6 r
* K6 X: ]$ D* h& E% X$ o2 }" Z) S6 g* N HWND hWnd; //消息窗口
; B+ f. Y8 j$ V: w- f ) @7 [* ]) h( x/ Z) y) z1 ~+ X. B
UINT wFunc; //操作类型
1 s4 X5 E6 [8 Y. d 1 G) _! o4 E" S- F8 X7 ]9 ?* _
LPCSTR pFrom; //源文件及路径 # P; L: ?# o( T0 p# @5 k7 a9 y
/ X5 V! A j% n3 [# s4 N- ^8 i( ] LPCSTR pTo; //目标文件及路径
D& ~; J* m: y* @# s
% E9 G) g! T/ g0 f: A7 Q FILEOP_FLAGS fFlags; //操作与确认标志
7 p e3 G. [. A9 l
6 I# Q9 J, g) K1 y3 y. @4 t BOOL fAnyOperationsAborted; //操作选择位
9 l: _ J0 H; x5 q& Z8 i0 e4 `4 n0 Y: e
, q' z6 ~% D/ a# g LPVOID hNameMappings; //文件映射
. Z! N3 A! t8 z: W0 o
# P9 f% Z* c& O9 Y$ t" _$ U2 e LPCSTR lpszProgressTitle; //进度窗口标题
. T" r4 N1 j }& ^+ i1 Y 1 J& W/ d. f- T: p
3 W# O% v: W% [: T5 B3 H& A
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
* `: [ y, s: \; Z9 v7 r1 C2 \
, m1 \* F+ C! w' W' F6 C2 [ 3 |- G* U( `( D! N! t
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 3 n8 h& Q2 @! s+ C- V
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
2 A4 D6 ~1 b( M& t; |文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
# Q* U# ^0 t7 W个,则应是: # V# _; d* v8 z
$ L9 j- t( [& } ? p char pFrom[]="c:\\windows\\command
9 T! l4 `8 w- _3 H8 b , g% z" u: [8 ~
\0c:\\dos\\himem.sys\0"
: o* I0 ^/ C3 S% N1 T9 D4 T! Z 4 J6 U2 P, e; H3 M: T1 y, A( `( f+ Y9 B( f
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 ; t( F5 u6 {- i
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 ( c( L0 z" v7 n! A3 X, B
要成员,它指出将要进行的操作类型,是下面的操作类型之一: ( \7 a' \, F4 Y ]
{% Q' U( L: Q& W4 y; ^% k& s4 I ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
/ Q) g/ Q9 V, q; y
. o+ J m7 a8 S! R ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 6 P. _% P# X+ [* s7 B; V
* k2 U/ V; j3 v! E( N1 X * r J# A g3 G1 J
---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 + Z6 g8 q) U$ i) H9 P
' y% u3 a2 r( n! S% b9 z ---- FO_DELETE: 删除pFrom指定的文件。
, i% Y7 ]. v9 X9 c0 J9 v
) G ]) h- {; O+ b. z q+ j4 o---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 3 f, b; V$ Y% L3 t& X
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
% u% H# f6 H8 }+ U/ P) D+ U% o" n; g移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
* A. z9 v) w. w' F' j在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
/ V) G1 N4 r5 r组合。 7 a* l- U* N# U- o6 i
8 B' f% r# l8 ^6 n4 Y: h& F8 w ---- FOF_FILESONLY:不执行通配符,只执行文件. 9 R: t" i% w/ a6 o# z* e# b
, p E" J' I& v5 t
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
" ?7 t" Z6 Z6 v E* B5 Z E- i. ], _2 y- `/ D
---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 # n5 c v# B8 g$ Q
候,如
! n% l( w% v2 x% [; y 果不设置此项,则它会出现确认是否覆盖的对话框,设置 # p" @$ J L, ~( K$ D& s2 W
此项则
) j( o7 T0 w# e 自动确认,进行覆盖,不出现对话框。
$ n: A& u: E4 j0 K( J5 G; [9 ?7 ~ / K3 q Z4 ]3 U5 c5 S+ t' H [
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
/ C4 Y- ^7 H" m7 f& A( K" U现错误 " r6 q5 | z& Z4 t9 \
时,不出现错误提示,否则会进行错误提示。 6 ~0 i, J. V4 w1 k1 C! {, w
& M9 w* R, B5 w1 [" F ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 8 t2 `5 ^4 I* \0 z
进行更 , \3 k" N/ |8 D3 z* ~
换文件名提示。 - f& _, r9 w1 W$ l
1 G% G+ Z( h0 Z. E ---- FOF_SILENT: 不显示进度对话框。
9 j$ `# v( m8 Y4 V % d8 t: o$ Q4 X$ R) Q
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() 8 S0 d! \, r; Q: `& T C
函数返
; F0 s. ` ?. Y6 h o/ P 回正处于操作状态的实际文件列表,文件列表名柄保存在 % I P2 N: r6 t5 n( W- Z
, S, U" p; v ~6 a hNameMappings成员中。SHFILEOPSTRUCT将包含一个 / m; L) c4 c7 t) M: k( e
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 ( u7 E, t- J6 y( q- G; t
个处于 ' ^& m+ a5 `; r4 T5 m
操作状态的文件的新旧路径。
i1 p# Y5 W; q" N/ h1 M0 f
7 a0 S' a" R3 [) s二、 实例操作
. a: O, |4 r5 C+ k- K. k3 ^) v
% Y. n# R O5 Y( b, ?---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 & {5 }7 E* T7 I0 D. m0 R# d7 s
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
* w2 t; O: d7 E& [工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. * s! J( R5 ` V" h) c# ]0 a
cpp的OnCreate()成员函数中加入工具栏。 / l" z1 i) n- _! y$ J9 r
. B) n- p4 d# D/ b5 W9 s2 R9 w
if(!m_wndMyToolBar.Create(this)|| - E4 ~+ ~8 a# v6 R0 ~
2 Z! O3 u, o l- H v
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
( l8 r, ]" q3 A( d: ~2 n( @6 w6 ?
5 Z2 A( x# i/ a) H {
/ r4 @3 E& { w+ T
$ R$ S' m6 m+ b1 S$ ?/ x/ ^ X TRACE("can not create the FileToolBar!\n");
# ^) V4 E* Y) E# q7 k
6 C: V) I: D' G: _, U2 z 7 q7 C5 T ], }% c
return -1;
. |' V# s, c8 G4 O* _: }* z, _ & V- [/ p; B/ \2 j* ~. a
}
# S* y* K. D/ E( y5 g4 e) f 7 Z [8 E5 B5 }( P& X
# S) K8 W8 x' S8 p) o0 u" b
---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
8 m) s' `6 G5 TID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
( K4 C- V5 X) ~+ e4 O 4 T& @. g! S" U' g
void OnFilecopy() 4 ~, N0 C8 C) q8 j7 b* R, d% q
{ 3 L; b: @( ]/ O. ?9 D" e$ x
int nOk;
# q- a- f/ |" I- L* |. h$ {6 s char strSrc[]="c:\\dos\0c:
# X6 r1 p7 t, b+ O4 O6 k! f\\pwin98\\command\0";
8 b; Z _) V: A: i: i //可以改变源路径 ; F/ z! u- H7 H2 I
$ N% o# P# Y/ y* v5 o char strDst[]="c:\\temp\0"; 9 }8 L5 q* x9 @, O
//设置目的路径
# P: z2 H3 E% ]% q# `' ^: n " I5 r2 ^3 `0 s6 h& o0 k& Z
char strTitle[]="File copying";
7 L7 M, ^7 F0 q2 D. H5 x d //进度题头
( G& _6 L, p; L0 U; i3 T' D
6 i8 G# Y6 m7 s8 Q4 `! H) D+ W* T SHFILEOPSTRUCT FileOp;
2 _; R; U3 A% j$ t
7 f% j* M q. K0 Q |5 u FileOp.hwnd=m_hWnd;
7 d* T2 s/ e/ [
0 ~( D- P- \4 T* v FileOp.wFunc=FO_COPY; - O% ^& c$ ?, Q$ r t) m
3 N3 ?4 M) x+ v0 Z7 A3 ^
//执行文件拷贝
7 l3 R. ~0 }8 ]3 L; l ) m# h9 p, w0 Y7 u6 X
FileOp.pFrom=strSrc;
3 k( ~1 N9 k0 c9 z0 B" D; n4 n
6 P' q" ^1 \1 l FileOp.pTo=strDst;
, d. V5 f- x$ O% c9 Q; }" s* l& v/ z! Z
9 [- i7 T: ~. M) g& t+ k FileOp.fFlags=FOF_ALLOWUNDO; * ~3 A) k1 \. u
. ]4 }- n5 P' H0 u
FileOp.hNameMappings=NULL;
* O' v7 ^+ c- E( q 5 |. w& E9 r3 d! V+ `: L, v( n
FileOp.lpszProgressTitle=strTitle; K! h; j& C0 C) K s& R
# b: i8 \2 Z, ?& a& Z; c; ~
nOk=SHFileOperation(&FileOp); * z) Y7 I6 I9 u* T! @
( ^, [- M8 E B& B: z
if(nOk)
$ O$ s' y# a* R9 T9 E/ n" R# Y 9 F) P. ^0 `$ @+ @4 L' x l- r
TRACE("There is an error: %d\n",nOk);
) E8 Q# ~1 I! G3 ^/ ~
& G& v1 C! D3 n6 ]6 Z! w else
, C3 r* N/ [$ I1 x( k' s 9 I* A7 ~- s* q9 f; {' R# l& K
TRACE("SHFileOperation finished
* k5 V$ \6 `* k* x) p" F3 Nsuccessfully\n"); ; e) X3 e' Q5 J
: E: ~, G6 @, i' u
if(FileOp.fAnyOperationsAborted) % R& T5 o, k; y, w+ y8 t) v" t
( d* U, f9 Q/ |4 R d" A1 \
TRACE("Operation was aborted!\n");
3 N( G* _$ ~2 i4 p5 [5 ? }
) d. t" j. b" O: _
" @0 Z" N a6 w+ E6 x; ]- i8 u
) r$ e0 S# o: ^三、 结束语 - ?2 ~. p: n- P3 w0 i
) f+ \; ~0 H. E6 O H7 [" O: [; R; w x
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
* v# P1 E$ T3 Q p的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
6 W4 r/ s6 J# m* w系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调
! \8 V( x+ w! @5 u用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
( ?- T. ?, [3 k! \- h C! d " {" P' ^ N% A/ I; X* B2 k
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
: O$ G) C1 W' d- r$ t, H到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
1 v2 [8 a% t* {1 @$ X地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |