|
# m( `' ]) q& R6 _" l
湖北工学院图书馆计算机室 2 L! ]7 m; k! T3 Q+ L
张明武
! `' ]2 W+ r( f/ m, u
' M) u. E% F2 ]' z8 A2 ]; H. n---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 * @% z( R) c) x
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
% ]: A+ ~8 K& k( k! A+ w1 i# f、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
1 G6 ?; [. x9 \" w9 ?) I1 Q区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 " Z- ~" R- O, g) c6 d3 s& R* B2 b
库进行备份,很难达到最佳效果。
- A) Y n( n& m* Z
* a) B* \7 r% }/ L7 M( U, }5 c- f4 X3 ]---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 ! R5 x/ t- V5 A7 V
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
- A% u6 x {% u, l. ]可以直接对一个目录或目录树进行操作。
1 c8 d" e; e- g # }& V4 y/ B4 w" X: h
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
/ O9 d* x9 p" t0 p! M文件的拷贝操作。 : G& O, m$ D% C4 R0 \
& n; V; H- l/ t+ A, t
一、 原理与结构
0 w6 x- t6 ?% B5 l) j+ Q
) M* c K' M" u* [---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 ) X5 J# f" f# v( W& A$ j
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
" A1 B7 \* N; x% n
3 U% ]1 b: b1 F, p1 s& w( Q4 P8 U---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT " R5 H' B* C% W; g9 F
lpFIleOp); 8 j- P f+ w5 c* r4 ~0 A
3 u$ d% x& \( c/ L9 T# Y' F---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
) M z8 d( F: J8 w, e下: ; U0 v5 I! u3 t% ^0 c$ c
4 z$ I, g3 U$ n! b0 l; l
Typedef struct _ShFILEOPSTRUCT { 3 ^! f, L5 [7 ~
! J3 L- K2 ~; y5 f# O/ F
HWND hWnd; //消息窗口
+ l& i9 \* c' o7 h! | ' ]. s2 R1 g' b9 h+ g* J6 y8 ^
UINT wFunc; //操作类型
0 b9 a( e+ |0 _. I7 S$ [; B - f- ~: O9 ]3 l% A+ B
LPCSTR pFrom; //源文件及路径 7 o0 R! Y+ I1 O8 Z
- F4 l0 h& g. {$ o LPCSTR pTo; //目标文件及路径
# j1 o- u; [* F5 q6 _; R : ]# p! z7 v% h( P- `% U+ H/ F- d, g3 `
FILEOP_FLAGS fFlags; //操作与确认标志
, }5 x2 W1 ]( ` * Q! _3 ^! N. C' t$ o& } u
BOOL fAnyOperationsAborted; //操作选择位
- c3 d0 S. T [: Y - C7 {: p% k9 n/ v
LPVOID hNameMappings; //文件映射
2 y9 k5 _! I% X5 P7 D7 Q ) S" v7 v+ }6 O6 E$ i& r# E
LPCSTR lpszProgressTitle; //进度窗口标题
: }4 Q. `" o, W, L % E$ Q2 o' g: |" A) l A, T
! f: o: U# A( D9 i } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; 9 a3 C8 L) Q. ]1 X2 `% n7 E
W+ i' p# Q5 `$ I* z& T
( C- A& }$ M2 ^
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
7 _. j. }1 T& ~与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 ( e7 w3 V, K/ j/ ~$ C, x t2 `: X; q6 N: j
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
+ D0 r6 C/ Q P4 B1 A7 x) x个,则应是: ! F1 D! R D |2 n$ u
`. c; ~! V. y/ U1 n0 Z char pFrom[]="c:\\windows\\command ! z5 e7 r7 z4 v& @. |
, n! O7 w1 Z) N
\0c:\\dos\\himem.sys\0"
% L. u) G4 J% \- s! n. M $ o( `$ M8 ~- N
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 : a0 x' W" b& z' N7 Z8 s
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
" H0 b" @0 b# f5 M/ @3 A要成员,它指出将要进行的操作类型,是下面的操作类型之一:
0 B U7 r0 f( T2 M6 X
9 C/ i5 C( K% Y ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 ( i; ~( T$ c9 o
: ?1 g4 G, Q5 N e$ Z ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
4 R. S% H; T0 N- P3 o' b
6 Y3 y3 J; x1 J8 |& O0 U7 y
: Q) [6 X+ N2 v2 v8 f ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 . a7 r0 b# G1 r1 a" l
k i5 z+ F7 b1 s. w& J% A$ Q
---- FO_DELETE: 删除pFrom指定的文件。
' K2 s8 R% }" m5 C4 u, I* p% A* t * y4 F% A( m3 D; r9 [* M7 t
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 % `/ M$ u U# H
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 , F4 D8 O; R- S. A! R
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
& @8 _* A! c0 ?; s9 P( |2 B3 v3 G/ D在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
" O7 ]- t0 K# ?" ^7 u. w* f( g- t4 {0 A组合。 * u w0 j* r7 b2 K6 q" z
% m1 v7 D) G$ @8 p0 S
---- FOF_FILESONLY:不执行通配符,只执行文件.
4 S7 `% V; d/ ^% d- C+ }! \& Z
3 K& l7 N- j, a: g4 C5 D ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
# A# V# g5 f! ^% W; V& ~" V
2 O4 j" w) [7 E) q$ T! l( i3 M ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 + F8 U* V1 B6 ?$ n5 A4 E, r
候,如
4 J, n# ]3 D, g: t0 ?6 I4 u 果不设置此项,则它会出现确认是否覆盖的对话框,设置
. S" j% n! n7 h2 u' V) V此项则 - I' }, x) T O' n& {5 n1 ?; C6 v4 E8 T
自动确认,进行覆盖,不出现对话框。 3 _) x& u, Y% {. s0 ~5 \2 t
6 v9 }: X: Z/ Z( \ ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出 ! J4 N# A o0 w5 n' B/ n' n
现错误
6 t% y7 R3 |0 f& f; f 时,不出现错误提示,否则会进行错误提示。 & F. b8 S- V0 I v: i; T
+ y* Q+ F7 c) t" J2 G3 C) |3 K ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
' |! q O9 X. f1 [8 h进行更 * L! S* a$ h! l/ H
换文件名提示。
: i9 U' K. ]! K
5 [+ v2 \4 U3 }- {3 g+ N1 @5 r ---- FOF_SILENT: 不显示进度对话框。
0 Y m$ D( G" w( Z/ Z) ]3 r, ^ 6 X; l3 C8 ]6 p2 q
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() ! P4 Q# ~- u4 i/ ^) i) t, \
函数返 8 `5 ]% K1 L+ }9 |; [9 |
回正处于操作状态的实际文件列表,文件列表名柄保存在 * _* X' v0 C/ ~5 l
5 a" i7 w2 A2 w
hNameMappings成员中。SHFILEOPSTRUCT将包含一个
: Y5 ]: ~) |; n. D SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
6 y; i( _2 V, p+ t9 K个处于
5 C, [ ^- L- [, Q 操作状态的文件的新旧路径。 2 h! y S, i9 b1 d: |% i* w
! J" T5 Q @( B: H二、 实例操作 " p, l' i( X& |: C, v
% Y* o [+ U: P+ _' q! h. g---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档
/ i2 r# r) u' F! v0 `界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
$ A- S5 M5 f# H; V9 G; T工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
9 ]" S2 l4 F( h9 C* gcpp的OnCreate()成员函数中加入工具栏。 ) i3 _2 B8 f# H, r* k9 E; |
: Z5 w! c. s% L: w
if(!m_wndMyToolBar.Create(this)||
6 j H0 U7 e6 u) ~& E) [ + t3 B6 D& i! V$ n* ^$ L
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
. W2 u& L- ~% t, Y7 x 0 p/ x! [% @1 _) g
{
. o7 w2 X/ t" A1 a9 ~3 } 9 Q& L! T: L' Q/ g$ l3 Y
TRACE("can not create the FileToolBar!\n");
1 c: K% m1 w- C0 _- Y' h R3 X 6 i1 D& u8 z2 T+ L
$ A3 s0 h3 m8 j% r. I: V4 O return -1; 9 `, Q% |7 f" a& g1 X
: T q" y* V7 a }
. z3 U; t# E5 v
/ a- j y" ~' H1 S& e 7 r: _8 j# y3 |7 h8 N. o
---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
" g. m. K/ U9 GID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 $ p6 g# a4 U0 {5 M# o* U
/ ]% f6 N; p2 K/ A+ e) t
void OnFilecopy() % a+ e" c: E& U
{ 0 b6 U) \1 d* O3 ^ Z0 Y' ?
int nOk;
) d3 v: i/ Y+ T char strSrc[]="c:\\dos\0c: * k4 M$ V3 U1 P! s& i
\\pwin98\\command\0"; 2 W7 w3 o1 U, t9 p
//可以改变源路径
: o. l7 T( X. `; v3 C
# M3 w* K' R+ y a7 z char strDst[]="c:\\temp\0";
; c4 A9 r' L8 J! S" V5 o //设置目的路径
8 v7 I: i/ N$ V9 K. _
2 Q) r: p2 `/ @2 b char strTitle[]="File copying";
8 h7 I5 u2 J2 w; N+ ~/ m5 ` s# D' X //进度题头 1 P% I" x1 B0 s! M1 T f& I/ }
2 U& | Z# Y+ a- F( L: @
SHFILEOPSTRUCT FileOp; / D6 b/ ~' }: I6 G% x* X- _
8 K/ y( X; W# M& H FileOp.hwnd=m_hWnd;
3 `7 o- p- f0 _2 k# t; N1 H
1 C/ `1 T& h5 c ]) D1 ` FileOp.wFunc=FO_COPY;
1 h- l5 d* o" j
S p3 B8 P/ T7 a3 |! X2 ]# p# _ //执行文件拷贝
j! }3 i# [+ f$ P- B ! ^' i* E# n2 f/ R
FileOp.pFrom=strSrc;
$ ^, L* i1 ]# s1 g
3 J) _+ b, o$ ^, R; d8 J FileOp.pTo=strDst;
3 c+ i- R$ M% s5 E, M. b ' P/ H5 _! D5 [( Y* W
FileOp.fFlags=FOF_ALLOWUNDO;
1 r3 i, c: P# ?' `" W% q& D* I 7 F' r* ^$ ]0 Q9 D
FileOp.hNameMappings=NULL;
' ^& ?; d! f' I' f9 f' h6 M 4 J# P% x( [1 X3 b* B
FileOp.lpszProgressTitle=strTitle; . Y. k/ D! D5 s
6 Y, M. |5 V( `6 E' p& [5 I3 y
nOk=SHFileOperation(&FileOp);
, F1 {! z0 M+ t& h4 ~+ q0 P
; q* z4 g5 I; }% W if(nOk)
{7 o3 l4 c+ m
, S$ H# M% U& R: d" ~# f$ x TRACE("There is an error: %d\n",nOk); # c$ p/ c- R. X, w2 s2 @
$ c/ ]- U7 P) B1 r0 _# E+ F8 F
else 4 o0 a e% r2 z4 G q
6 Y, D% \$ ]; f8 L TRACE("SHFileOperation finished 3 S3 V' w. f# G; F
successfully\n"); 2 h6 r$ a' M w p# \
9 e+ |: U2 o3 }7 H
if(FileOp.fAnyOperationsAborted)
$ `, F) E; J! ~) @1 N; m
5 `2 J8 ] Y: I7 _. S; j/ m TRACE("Operation was aborted!\n"); : _8 u2 _ J2 U' u5 j- K. }) B
} 0 \ l. v- \. m' _$ W2 v
0 `' {0 @1 o9 S3 s f& Y
4 J2 ?- }3 S* f9 t) | Z4 y3 L. D
三、 结束语 . c& Y# F Q, S6 g8 z
1 i$ X0 [- [" P0 N: r% q) U
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
8 q. z5 K" n2 A2 o6 e的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
6 Y7 a3 S% B; G( T5 K! f7 y系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 5 }+ _/ w: r/ y6 ~( c5 T3 _
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
) v! W( x9 b2 [" x' r
6 W* h( y2 R! p* Z8 K, P9 ?---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
! ]# s- Q2 h9 j4 U; z0 M: k m- @到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 ( i0 c6 L8 R3 @
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |