|
9 P2 Z2 x5 A& b湖北工学院图书馆计算机室 Z8 u* H* N7 p1 a& D8 l; X* k+ u
张明武
! G" c F0 X4 c! Z ( j7 u5 ]; ?; i8 |
---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 5 d: W# w( \9 ]$ K: x; K4 l
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE 1 K p3 x% v" O3 K
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
5 t6 {1 u9 H- b* o区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 : U' h7 O; A& {9 p" |7 E
库进行备份,很难达到最佳效果。
4 Q6 w$ M4 w9 R. i# ]! g L * T4 Z5 r9 c& @
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 3 G- \6 H' t+ |. {5 E
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
4 h `4 E( t$ Z0 _& }: @* F可以直接对一个目录或目录树进行操作。
0 ]4 c4 g1 \) t7 f
. u5 K; }7 y8 O3 Q---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
; ^9 [7 H; m! \: n+ g- {" B文件的拷贝操作。 8 B: e4 `: g4 \
+ P/ K) X- a8 q: a6 A一、 原理与结构
' j# X* t# O! ?; U, Y1 [* L# E) S) N
7 h( f) n- D) ^, N* j---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向
: V4 `! V& G8 a/ b* s" ]SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
9 o# i) c0 h) Q. f
: V; {- O, _0 ~" \---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT ( M, X2 `& F+ h+ E6 S2 u$ r; r
lpFIleOp); % N: O! r( z- I1 ~4 B1 p
& D: m: r1 P" g* K( y---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 C$ V/ k2 r1 c# I
下:
+ R( |! H8 U' l! t0 W7 ]; s3 t 1 H; V; B) X O# P( f/ C5 n: n
Typedef struct _ShFILEOPSTRUCT { + l5 N' f; g" n- ?+ ~( I
5 ?. r! D) x7 j
HWND hWnd; //消息窗口
6 \: A) a$ p6 ~2 D* } 7 _5 W* k# X3 T9 t
UINT wFunc; //操作类型 2 O8 d& e! a# s8 L. e
1 w: J- ?. U2 o9 \* E% u
LPCSTR pFrom; //源文件及路径 6 f( W8 A8 x& s% I1 P; ^: U
& E3 E2 n% G- K' o% Y LPCSTR pTo; //目标文件及路径 " E! q- R/ H4 |# ~7 d1 s
( i3 e2 ^! |! Y* D- e FILEOP_FLAGS fFlags; //操作与确认标志
3 P; J: c) w0 ]: j/ m) c
' }4 H, W5 L; N9 j/ A7 w: e. E BOOL fAnyOperationsAborted; //操作选择位
+ \2 |/ x4 j/ J, U0 \
' k* W- R+ v1 u5 u' g LPVOID hNameMappings; //文件映射 9 q* \3 i( ~- r0 L Q
4 o+ P5 q& {! ~ O: ? k; @ LPCSTR lpszProgressTitle; //进度窗口标题
/ Z( ]# {5 _4 c
1 O o7 d2 [% }* U2 r) ?
, O: q: Y1 q4 Q y9 B4 x+ u } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
8 M/ T5 E. J7 Q; v5 }* V
9 B/ X) C, q8 y) K8 L1 j2 ~$ a/ ` " l1 q- ~, l1 n
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 6 ]0 m6 H' b) r3 n7 ~) f) V" k
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 [# k3 t& E. p/ V' _# v0 l
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 ( ^0 s8 S! f( i7 G
个,则应是:
7 \" v4 N* x! Y) l: l7 u1 {: t # j/ N& L8 {0 w) W6 s$ z: s" r9 `( g
char pFrom[]="c:\\windows\\command
: @9 o' K. {" V+ O$ P% i% c% f
2 [7 S/ ~4 j# k8 C9 [0 V1 V \0c:\\dos\\himem.sys\0" 6 {0 N6 ]/ i# k- g' Y
+ ?% `1 K+ {8 B---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 5 `1 F: x- f, b% |
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
& T! c- H* V2 f* b; }要成员,它指出将要进行的操作类型,是下面的操作类型之一:
, g, s& W0 t- w. Y6 I2 I4 s - @) H ~+ o3 H( j- e
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 6 j! W! @$ f6 _
* U: i) d/ X3 m2 u! h2 F
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
7 F" `9 V1 t" Y3 h/ H) Y9 u
+ r4 z! i ?* F
: M* t$ e& S/ x ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 : T# Z& g. n3 d |5 Y
2 |3 f* I8 q4 t4 J( T ---- FO_DELETE: 删除pFrom指定的文件。
0 N# f2 z: n% Z+ t" s2 t
2 G- E0 h2 o x7 a% P---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
7 u3 |( Q8 x, |程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 4 N) B% a3 a. `' x
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 5 o1 [, E1 O1 }! C7 O
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 * J6 ]; l8 m/ t, ?7 w
组合。
; H6 f2 l( i/ e8 U/ k/ k $ h* I+ A8 q# I9 v9 K) O" M3 C
---- FOF_FILESONLY:不执行通配符,只执行文件. 7 v$ v3 X; K7 k- n2 D; C
, Z3 h; p3 f5 W9 W2 F
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. * ? t4 T7 M+ J- A- S
+ O: W: v l, f( ~" X
---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
( a! G- h8 V7 d4 U7 I候,如 . Z8 L6 k9 M1 b3 W5 M& r, j/ _& C1 Q
果不设置此项,则它会出现确认是否覆盖的对话框,设置
+ y# h+ p5 b u此项则
: v; S0 U1 \# v, B2 a 自动确认,进行覆盖,不出现对话框。
4 F4 {+ x* g. R4 i7 C ( G; H8 i6 ]; W9 _3 [* ^0 L
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
7 P7 k, ]$ u1 K O现错误 6 w m; M1 t4 a2 J/ A0 [
时,不出现错误提示,否则会进行错误提示。 ; w$ O8 |" H! b0 {: O
4 T" k* x( g6 q$ y( }4 p$ L! n+ k
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
0 e% b' [. t+ k* S2 x+ }5 ]进行更 * i# X0 D$ R+ B( _
换文件名提示。 5 J! X- ?- J# F6 j+ F
2 U1 d9 T9 ~% H3 [ N# g ---- FOF_SILENT: 不显示进度对话框。 3 O6 r4 H' v7 g1 S9 @+ S; y
) e# {4 o2 ]8 v$ N
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() ( }8 |6 S: V0 v* z9 @ `
函数返
& b7 o L8 w9 R* ? 回正处于操作状态的实际文件列表,文件列表名柄保存在 . Q c* y( q; H- M
9 A: n; H8 o* r' ^, n( O9 i hNameMappings成员中。SHFILEOPSTRUCT将包含一个
6 \: s5 h; ^+ @. B" H8 c3 { SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 3 {0 J+ ~. v/ y/ O7 e
个处于 " ]$ T$ ~0 I$ @9 d# W) w
操作状态的文件的新旧路径。
0 p6 q; J! G [0 e4 c4 u & K+ ~; `0 c9 y, l) U) i' g7 M
二、 实例操作
, a$ @- W: K$ p- H0 F/ R + k! R2 ~/ u% o1 c D
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 # c5 y3 K# e5 j% H! V4 `4 O
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个 9 K8 L3 Z# ^! h0 J
工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. 8 @5 E0 d- e, @: c# o
cpp的OnCreate()成员函数中加入工具栏。 7 F( S% |; i' M( B( [) ~
6 ^" n5 \# _# R) K8 N8 M if(!m_wndMyToolBar.Create(this)|| 1 Y: N0 w* c2 j- ], T( _* M# A
; f/ o. T: J7 J: R: { !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) : j9 S, I' s* L% u
8 E$ m V& ]* q4 x& I! v
{
6 ^% ^. r+ j& n3 u9 ?6 V ( U6 b( x- z2 p
TRACE("can not create the FileToolBar!\n");
" o0 e8 R' b! w# {' ^
1 C. j$ b' s& E$ n A 7 i& y- ]/ E/ u6 S0 i: ~
return -1; ( u: c+ c: Z8 S' P% Z. K" ~
: x% p+ a& S$ I: k- N
}
, S2 ^% q n% t8 n8 W! a3 e
T o8 h" h2 _4 o( @# E B 1 D! j5 c% H1 X% f9 B- b3 u; L
---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
$ |3 J+ z/ L" ^# K* Q i' B1 t. {ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
; M3 I- P8 K3 s b# Y3 ~. }( y. ~% U
/ H7 G: i% ^$ D* u# @! P- p void OnFilecopy()
2 w+ ^/ }6 V+ x1 h5 H {
. \! z" `1 v0 r0 Z int nOk;
2 \5 m0 g; g) T2 G: Z1 E. ^ char strSrc[]="c:\\dos\0c: 9 M% l( b$ o" G# M8 M
\\pwin98\\command\0";
i% O5 y: H: k7 g! A/ q //可以改变源路径
$ d! w; v" v" f6 l* J6 R 4 G" e/ g7 ~0 L: k/ T' u
char strDst[]="c:\\temp\0"; + ^, R9 E) `4 r
//设置目的路径 f; u- A3 g8 u2 L% |
1 W" W( H7 o- H. Q! W7 H# F char strTitle[]="File copying";
' i) G) a# S! _0 L5 t //进度题头
: }. P0 z/ n W3 K$ F/ a1 W- V" D
; t& o6 G7 x: o/ x SHFILEOPSTRUCT FileOp; . y5 u$ p- ?. ?2 R
7 V& F3 l* P: }1 b/ H6 U+ N FileOp.hwnd=m_hWnd;
% z- k1 a9 t+ @! ? 1 J% L" _- J0 s9 H& P9 |
FileOp.wFunc=FO_COPY; 4 ~" p$ J8 _8 G. N- `8 q a
( M) [) P/ G6 V //执行文件拷贝 + t% {1 b G- L0 w6 x3 o
7 j' s1 a& ?9 {0 g1 B FileOp.pFrom=strSrc;
% u5 I7 ]7 }; I* Y ! C& M+ o* c8 Y5 o5 |* T5 M
FileOp.pTo=strDst; + z$ M' M) Q9 @/ r' Y' O
P1 I. |8 t. c* r FileOp.fFlags=FOF_ALLOWUNDO;
8 d% s* W' I. f3 N/ x " K# U5 A1 e, b1 ^+ }5 W( u" J
FileOp.hNameMappings=NULL; 4 A6 J" S q% m3 {3 q: _. h
( ?" `+ I, v( N: T" X
FileOp.lpszProgressTitle=strTitle; 2 @/ I* Y( t! |( x
( d2 T& a- h( b+ {4 \) W/ b nOk=SHFileOperation(&FileOp);
% G, l) g5 P& y z
4 Q2 a5 Z+ r; k; ~$ R if(nOk) ! l) ?- b1 i$ @ Z2 r6 M8 T! ~
" \1 M) O% v$ I/ j7 T" W2 U! H TRACE("There is an error: %d\n",nOk); R1 C) [6 O) K7 g, \0 U
; p2 N; Q) ]* @9 { else ( Q' P7 N) G; N6 x$ n6 X$ Y
! I- n. A) k& b% C' I6 F TRACE("SHFileOperation finished , Q- R5 ^" `5 g) Z* I$ Q
successfully\n"); : T" m9 {% e7 F& B1 Y
3 ?* @0 ^: U8 S3 a/ Z! p8 n% W
if(FileOp.fAnyOperationsAborted) 6 W( ~1 ?* i0 j6 O3 }8 M
" z! @( U3 x) Z; z2 p- p* U( k TRACE("Operation was aborted!\n"); 9 E; ^* _; W, u
}
& R1 _0 _' l! J+ F
* w; j% ]& R8 ]6 W ) d& F1 G9 U ^& o0 p) c; t
三、 结束语
4 b1 ^/ f3 H& Q ; x: F/ H$ ?$ l0 i A- i' c8 I* ^
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
" C6 F( b1 t) T+ k的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 $ o' @& ~ F0 i; w7 a) \# y
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 7 Y. B4 [( B& G! \" n9 D. q
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
8 f- ^$ D9 w" q4 I# b
1 ] P" P0 Q. s& ?3 Y8 \---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
7 O2 w+ k, Y2 {* `+ [到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 4 F( m- r) Q7 {# o; \' A
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |