|
" i3 \1 s6 n% U0 @1 L* v) N: j湖北工学院图书馆计算机室 5 L3 i( L) ~3 f& [
张明武
+ Z: V5 g* D* l) I$ D0 H0 z0 \
4 }8 V# q2 o8 \6 i( z6 z---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
1 K( T6 P V% V操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE 6 h U1 p7 V' o+ _
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲 # z& p4 l! |# D, Z
区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
8 [- K, i; M+ [' b库进行备份,很难达到最佳效果。
, b. Z- z$ S6 w/ K a" v0 `" x ) q' }8 b4 M- [
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 / g: _5 W2 ?' A. J5 T
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 ) R, u' v- _6 p) f
可以直接对一个目录或目录树进行操作。 ' z% k E! k5 q7 c* D2 |
5 O3 ^- }( Z. L9 p/ E9 ? h& u# _9 ]---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 2 {% _: Y2 L$ f# R. ^
文件的拷贝操作。
8 r* F ~! {8 W5 B' }4 t) N 9 A6 `' x7 q) R+ U5 _& K* o; i9 q
一、 原理与结构 . j. F L, S j% S! _1 R0 w* A
: C, L& p: [6 I/ e: r& }& |---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向
$ A: M# n/ y! Y8 B* `- k3 LSHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下: ) H. o5 S7 x4 d' ]. b* m5 p
& _; e( U" y- T6 _% K* Y& X---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT ( U. ], l9 q% p9 r% b) J/ Y
lpFIleOp);
9 Z1 X- A; m1 M: S {! R* Q
- g) |! T' D6 ?7 y- k' |0 C---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
! O& f( l8 @ E! ^' S ~2 g. @下: & g2 E3 B. p6 ~5 t* X
8 ~) R ]- D% J+ g9 ]' T
Typedef struct _ShFILEOPSTRUCT {
( S) S! I+ n+ G7 o, S
- e5 M6 }% i5 A HWND hWnd; //消息窗口
" v( I6 ]8 [5 g/ }" ]3 j* a
8 f1 \9 A5 Z4 g: i+ T* t! l UINT wFunc; //操作类型 3 n, g6 _0 x) @& {! T
% x1 r3 l2 k5 | LPCSTR pFrom; //源文件及路径
' z) x5 F3 n! T$ I8 _4 q3 d% H + Z1 v5 d# \7 K6 x
LPCSTR pTo; //目标文件及路径
6 Y, x( v4 l, v7 R+ H$ S3 n 6 n2 V1 n# V& v1 R. M" }1 s! V) b
FILEOP_FLAGS fFlags; //操作与确认标志 # T! t/ g: h. f# h3 e9 K, u$ g
; `6 G/ Y" _: Y
BOOL fAnyOperationsAborted; //操作选择位
" |: q6 x! |7 h6 _/ Y+ C0 \ E; b% @
/ d4 f* U% T' n- S @; f2 P" U- C; c& h LPVOID hNameMappings; //文件映射
- B" ?, F; m3 z2 ~ " ^" ]2 j# u; _# F, |% j* x
LPCSTR lpszProgressTitle; //进度窗口标题 2 J! d" b3 V, ~9 W
`% }$ ^8 ? r; M" I) k
. b1 f) P; Z7 Z5 v5 B. e
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
4 \& s$ K. x$ W( Z
, Q7 n9 f2 D* N$ a4 K# y / s, ?) E. p. D, q
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
% K: Q1 U$ ^+ B: q& V与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 ; k7 s' x7 b! `" F$ b2 B/ r
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
! q/ }2 H h7 k+ |0 A9 I个,则应是:
/ e9 r8 r/ |/ `7 W
" V4 q! p6 x: Z* C char pFrom[]="c:\\windows\\command M* ?# b6 f, V1 R# X" b
# e: t: B3 h7 ] d/ C. Z" c
\0c:\\dos\\himem.sys\0" 4 Y* a8 R y/ T( i; y+ \8 i% ]/ ~4 }, x
& ?; s6 j8 |; {" Y7 B8 v
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
. T! T0 k- a8 F! b0 K% Y2 A" _- `进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
# C- V" l% R% w) u要成员,它指出将要进行的操作类型,是下面的操作类型之一: 4 Q5 _% X9 |, L0 z r1 l
. T, Z4 }* @! s/ r- y1 h6 h2 C4 _
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 u' l6 A. ^+ V/ H" Y. m2 k
+ O* h( t, g( w3 N$ @
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 : Y0 m9 A+ x# m
0 B! C: R, F+ k% a& {) Q
6 t1 R. E4 d6 P3 |, \2 i ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
9 j1 t" R" X1 m& \+ `. K- z9 y* \ 2 o4 l0 b: N$ J2 j+ p
---- FO_DELETE: 删除pFrom指定的文件。 0 c$ }9 q- S3 [; e# Q7 F
6 f+ z5 e- H, Z# L. c* i---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 5 r0 `( \: `" J# W. P
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
$ Z0 K" ~8 m! [移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
/ \8 l' C# A# G' A在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 $ L5 a& c( q. {$ ^/ t
组合。 # y4 A: ?* {1 _
! ^* l6 x( f3 }3 T ---- FOF_FILESONLY:不执行通配符,只执行文件.
% D; I/ M2 M, W2 l 5 U* k) B5 t8 S( y" z1 M+ @. f$ u
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
4 {. \) e/ [( u
: l3 R3 L" T. n7 V6 \ ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 ; l) r1 o# ?2 e: R
候,如
@; `( U7 z7 z 果不设置此项,则它会出现确认是否覆盖的对话框,设置 % T0 F% ]8 s" }$ l: V
此项则
8 F- ~/ S. e3 i- M3 q 自动确认,进行覆盖,不出现对话框。
- q+ K5 C* a* D1 \, B* i 2 v# J' i1 G$ t$ E; W6 y% Y, \
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
1 n: B- |$ r5 w% Y9 y, ?现错误
; }, }3 e8 x7 y1 V4 H" l7 u5 a) _ 时,不出现错误提示,否则会进行错误提示。 4 y- j& S5 C# _
" {/ n: x& O0 l8 q
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 3 X/ E5 n2 y: Y
进行更
4 n9 Z U2 w8 j 换文件名提示。
1 i. f; M( i4 U9 D, s9 G; a4 i 0 T H/ G. q t: x2 O6 M0 I
---- FOF_SILENT: 不显示进度对话框。
+ m& e- P. c7 n& T8 t0 h6 ~4 d+ t. ?# F ) a4 M/ R. U: Y0 P' b4 M
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() : M8 p& G3 Q0 z4 G2 A
函数返 ; Q4 W) U6 J5 R" o& b( @+ u4 O4 w
回正处于操作状态的实际文件列表,文件列表名柄保存在 : ]. R8 S! [" w! x l
5 k- P* t- \% A9 ?
hNameMappings成员中。SHFILEOPSTRUCT将包含一个 + I& k1 V" h) I$ P2 X2 L9 D
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 9 t/ r$ E: _" s% U- S5 K/ c
个处于
; L C# k# h! F6 m, R7 M 操作状态的文件的新旧路径。
' v! v' ~" H; C* O- e- ]
" i# W; L# D, s9 v9 w' }二、 实例操作 * \# j q3 L- P" Y. F5 J) J2 d) z
; ~- v. J. i0 q+ V9 R---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 4 D& I/ `2 v1 A( z7 ^3 j
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
3 w8 n$ h0 O" H工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. 1 v# }; U6 o) D+ |# p; A2 F
cpp的OnCreate()成员函数中加入工具栏。
' I( c$ s) ?7 t: x 7 O0 H \; @9 m" y" m: {% S) |
if(!m_wndMyToolBar.Create(this)|| ; ], g q: a3 U- Q" Q* K7 {7 \
, _3 Y5 ?* `$ d" ?8 _" k
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) ( }8 F: D. T8 ^% G
& U0 t# `0 B1 x1 D: t, @5 ^
{ ' l& }" J% E3 E6 k7 S
& o+ Z7 p, E! L- J p2 E
TRACE("can not create the FileToolBar!\n"); - B) a$ M, o0 k9 B
3 ^/ r& P( J" d4 `, Q- M/ T, |
% h9 Q U# l5 J" E. k return -1;
% R2 ^3 I5 _- P5 D/ [ @2 _' v
1 U, t: i+ E2 k& K } 3 K. |% C, H l* d5 G, l
2 Z4 K* z- a+ m5 B. V! V$ }1 |
* A& o, c4 `- e+ n8 h---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
/ I# W5 y0 b" Z8 i/ w( jID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 ' g) s! a7 C; u
/ _8 M+ w- ]# y2 b
void OnFilecopy() & _* F7 Z* |/ l7 v- @. _
{
6 ?( K& B* m4 c' b3 v int nOk; * t9 `' T5 x- Y
char strSrc[]="c:\\dos\0c:
, v. y/ H7 @. s: `\\pwin98\\command\0";
2 P7 Y4 c l& j5 D- [- @( `/ K //可以改变源路径
0 g0 b: C$ K8 B0 t
5 P- R. n3 P9 w2 @ char strDst[]="c:\\temp\0"; - L: t1 a3 ?# E% h: A
//设置目的路径
8 ]' ^! Q6 \0 N" R0 ?% q) J
) T; W+ ~& w D! ]2 | char strTitle[]="File copying"; # A- g, A; p- `/ n" e8 w) W- o
//进度题头
, `$ ~% q4 D' d N2 ^* U: ?
, g. v9 w) N# x- N+ J+ x9 u SHFILEOPSTRUCT FileOp;
+ O! `7 l$ V+ h ( R9 K: N* f# b7 y3 J; h/ g
FileOp.hwnd=m_hWnd; 9 C2 @- h0 S6 K, [4 f7 c4 E5 C
, F/ M( J% J0 V0 \
FileOp.wFunc=FO_COPY;
( @: [. K) h" p8 y" a
, a( a0 n. B2 C) t+ \5 O" s5 K, B //执行文件拷贝 2 m5 k2 p7 N% F/ D# B
7 Q8 M) A+ Q7 Y* p1 w; Q) `9 s
FileOp.pFrom=strSrc; 7 e$ @9 }& C3 \" k5 \' E/ ~
9 v3 U0 p/ N* v8 ]6 X$ W FileOp.pTo=strDst; " u( H$ h3 x* @
# W6 S; |: l1 z- \+ ]5 ^5 |1 |1 O( w FileOp.fFlags=FOF_ALLOWUNDO;
7 ^, r' x$ {9 F; \ f 5 N' h& ` v8 K" t3 N
FileOp.hNameMappings=NULL; 9 ?) r7 F& O! Q) h% k3 X) a
3 n' v, T4 S& h6 \) f7 v FileOp.lpszProgressTitle=strTitle; $ }3 D0 F) t" N% R0 o; D5 v4 F
9 X( y+ n ]9 |* R9 C( R
nOk=SHFileOperation(&FileOp);
2 u* a2 P0 `# ^7 B- A) C5 G+ g `" ^. }7 k6 C9 o5 r3 a
if(nOk)
9 G9 f( k+ J+ j% m, u: S4 U/ g9 k# [
5 M; A9 ~& e6 o; x6 M0 `3 k TRACE("There is an error: %d\n",nOk); 4 I8 p$ B* O2 c! k
! J8 ~/ G% P, f$ E4 `: t' B
else
5 F3 x, n+ i W/ B/ S
& R' x& G: n5 f" ^5 a TRACE("SHFileOperation finished # B7 f% g6 m4 |
successfully\n"); a% H' `0 M9 H- f
5 R% V5 ~ Z6 Z7 z% V8 y
if(FileOp.fAnyOperationsAborted) ' U3 g4 z/ m; u: t/ m
; y0 k- E. x, p) G" H/ ]
TRACE("Operation was aborted!\n"); . X- B0 _6 g8 l3 {' Z# m- `
} 6 A; e/ d; ^8 h% q0 Y* A2 S: R
% y5 z, Q: W6 z+ a5 e& [
5 B2 x) c4 c c- H9 e \, ?
三、 结束语 1 R5 \$ T* z# B" e9 _% P) {/ N$ r
# F5 J1 T+ q- P+ T* Q! A& v---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 8 A& C% m. h0 |3 o m! G
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 5 }& K8 C- H) f6 O' L; R; ^
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 9 Q9 `& x' G" E/ T# m( N
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
7 R+ P& M/ x6 z/ L$ O* M , N1 _- q- {! D( @) y9 _/ l3 U
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 : l0 r# c1 C: n2 ?. C
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
' Z1 a5 Q; O) Q7 l' j* `* @地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |