|
/ M- v, u1 D6 g2 J7 X3 K# R9 d5 ^: ?
湖北工学院图书馆计算机室 ; w: A! s* J4 [" S- V" f! u
张明武 R, ?' G1 _1 ?, a4 f! P6 K
T5 s% s8 n7 X; K
---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
9 p7 @6 z9 e; _操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE 7 L1 q b0 a8 }
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
% W) F" y# \5 j# q) q区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
+ z0 W& s3 X1 C l: p* [库进行备份,很难达到最佳效果。
' b4 A+ a5 P# D8 `: m: C; g! ?
* J# ?8 Q# Y# j---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
% k$ u! M9 e# @* M0 r! D现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
7 G, g! G9 ~' ^) O可以直接对一个目录或目录树进行操作。
/ ]; ]" k/ U5 n$ x7 @ 7 \; t9 p3 q- @
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 . R! ^$ \8 e% v8 S
文件的拷贝操作。 4 L1 H. e, s- I3 V
/ ~5 [/ U- u6 I) F9 w
一、 原理与结构 4 ^2 u: O* ]: ^4 _5 p' @
% j/ V* z& i3 j, I" T' s---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 % a' A2 Y1 e C0 ]6 b
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
, o. c5 j3 ]1 n" \
. }4 _6 f0 S1 r8 f1 m5 |( i---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
7 r0 w% ]7 h! O7 [9 v' t8 C, |lpFIleOp);
8 E4 P: g& ?; v' I1 w z; l 4 W8 F1 \$ O7 F8 u. ^& G0 I( `9 g
---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
$ |. A% u s; M8 J0 s! F下:
! a* {7 p' z: }% b2 x* ^ 6 T) q, f* B6 Y! i
Typedef struct _ShFILEOPSTRUCT { 6 I6 S9 F# ]& j, w, J# n' ^
/ ~5 c7 D2 f. z8 U1 M5 J
HWND hWnd; //消息窗口
& g1 R6 ^* Y* {% O7 |
) x, r# `' R7 l0 J UINT wFunc; //操作类型
( y! P; V" x6 k; Y/ z: q
$ g9 S! p% n3 C LPCSTR pFrom; //源文件及路径
) W$ ?2 s" h* a! i! C
! D7 P; |- ? y- X LPCSTR pTo; //目标文件及路径
# s6 G$ |9 s9 v& a
6 P! I: h; R$ u6 [1 l; E FILEOP_FLAGS fFlags; //操作与确认标志
% |0 k ~: ?, v4 m ( G- l6 H0 s* l
BOOL fAnyOperationsAborted; //操作选择位
, _' y, m7 L2 x: b# G+ _ % M* i' r; L: |4 X# {2 G/ h
LPVOID hNameMappings; //文件映射 * f' J, x; g: Z3 V! k
! ^8 C+ v4 f( y" M" s" {$ O LPCSTR lpszProgressTitle; //进度窗口标题 ! F0 R" _0 R7 O* R8 c
' G( v) ]) `/ M
- X4 F# x+ T W; G& R2 T! `) A4 J! U } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; # S W0 C- r k
& \. L0 i1 b J" c+ X( |5 s
1 l6 k5 w, W" [
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 8 u M* E. X2 B9 v
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
) u. n. M7 M+ j文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 " W) O/ I P9 ]7 j
个,则应是: & _# e/ y! T# f. K* r9 N6 E! O
7 i; {- `1 T) K5 g) Y
char pFrom[]="c:\\windows\\command
6 f6 x4 y$ [" U: }; m+ [3 K2 A0 F) n5 P
( s s3 @7 B0 y5 z+ F5 G- V \0c:\\dos\\himem.sys\0"
z' r4 p' A9 |. M9 L% U 3 p8 |# ?. x. f& N8 R9 a
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 ! c/ t, a% {" l# s6 j X }
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 2 ?9 G% p7 ` z8 D$ k: [3 X* v
要成员,它指出将要进行的操作类型,是下面的操作类型之一: " r6 @& k( u" a1 I3 J3 E l
2 U4 S) t3 X# v7 P6 B R+ c
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 2 O9 r, G [5 B, k
/ T7 @& z* ~. I# Z( K ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 ) t# M. _9 t ]! K
1 B; p8 l# m4 { U# f X) R3 Z
" @) C" ~/ I' Z- F8 I ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
5 Z: r0 T0 |, n& F: \ ; E6 K7 e2 q2 J/ c% q
---- FO_DELETE: 删除pFrom指定的文件。 , |6 s6 O5 f) d& _+ ?$ j. k8 U
1 o* J" n6 O0 {3 c; j0 r---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 # v# Z( C+ B" H! q! d, s
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 1 V5 w2 s2 }2 T8 d- ^* I
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
( Z8 a8 I6 V0 `7 w+ _9 [. v在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 + k$ T \9 o2 ~6 H# v% U
组合。
; D3 e/ U: {# w" W" P: K$ s ! G+ `+ W( r, W) R9 \! z% ^, L
---- FOF_FILESONLY:不执行通配符,只执行文件.
, H. @: H' I4 E8 Z2 K {1 d 4 }! z" z! a( H1 O1 M7 I, c: a
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. ' \: y3 ~( m; O) [
/ f" z; z. P V5 ]
---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 ! {3 P* v1 L P0 R O( b3 C5 u
候,如
$ T! q: X5 B n8 a# Y# D# w/ i 果不设置此项,则它会出现确认是否覆盖的对话框,设置 ' p+ l( z& K! m! O( W+ Q
此项则
) ?( y* ~. h5 a, e/ B" K 自动确认,进行覆盖,不出现对话框。
6 t- ] ?4 `, z4 o2 \
" ~: d7 E7 j2 b- }% s ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出 $ {; e1 w) Y2 T: k
现错误 ( w. `) j- g6 e& {
时,不出现错误提示,否则会进行错误提示。 " L" |- i! t% U8 Q M
+ R& q% f' y Y9 f
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
7 e- i8 m5 {) C$ W: F) w5 A进行更 $ w. B0 x g) p. n% [
换文件名提示。 & _- m% J8 y( F8 V. ~. J. \
& H* y* N9 l8 |9 y
---- FOF_SILENT: 不显示进度对话框。 : N: C+ r# l0 f
, B" Z" O% D! d; ?% O5 _ n! y$ |6 p
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
Q- Q: ]" S$ f) p1 L! R) C4 F7 V2 ]函数返
$ w$ A$ j3 r! E" |8 e1 @9 U; R; K 回正处于操作状态的实际文件列表,文件列表名柄保存在
( g+ l+ U% {" S# n% C7 P & u" p; b$ P: [( B
hNameMappings成员中。SHFILEOPSTRUCT将包含一个
) C: X* L( I1 S: n SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
" Z2 F& S/ Z& X. g: c$ t8 P个处于
) ?9 E7 B0 F* J0 I/ p- U 操作状态的文件的新旧路径。
! V2 f* S2 C3 N' p# O: Q9 |
, `7 B R+ K0 t1 N8 G4 W二、 实例操作
# ^, F5 J$ b5 D& @$ P* n! }0 r9 L 9 m% a* x( o0 d: q
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 1 X1 V. s" V+ Q8 o9 ~; X$ k
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
' G" H; X/ T# `! ~5 Z. M工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
" T& `- |- r6 l$ u% ]: F' R* J( acpp的OnCreate()成员函数中加入工具栏。
" K! I* {# }, z; s" S# o * p, {. _5 n& @! D$ T$ W8 Q" H
if(!m_wndMyToolBar.Create(this)||
$ s9 F+ i# ^/ n0 q; r" G5 Q 3 C- i) Q& S: v) r; E
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
) Q/ u, l4 H" ]$ l& I ) k) s% d, R5 p) }* d1 K
{
% m6 `, g! g0 N 6 K4 t. U* l2 P4 T) _ P& Z
TRACE("can not create the FileToolBar!\n");
3 b( | O K) F & B6 R1 Y; i: k) c* c' ]
x1 t4 J; E8 _ return -1; ! D; S% n: n( ~* T' |* L8 M
5 v5 c7 I, c' M' F* S } / k! ^8 _$ ~- J& O. O% |9 J
$ v, t, y7 l, A. Q. \
: L; T6 p5 S9 z( I7 G---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
: `9 ~6 C- }3 G6 X# P2 [& NID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 / i# {. ?% t6 a7 ^% e8 L
$ S' R+ y' U* M2 h5 z1 `5 b void OnFilecopy() - P" A5 E% k# o! a* k$ N
{
5 z0 E% J x$ ?+ E0 a) e int nOk;
3 {9 L9 I: G6 {; x1 m char strSrc[]="c:\\dos\0c: * H& l0 F( S9 M: U
\\pwin98\\command\0"; ' _" Y1 w- d% G6 ?) H6 @4 ~4 S
//可以改变源路径
) m8 a7 t5 Z7 [1 x$ o; d/ Z
! p' b1 {" _! x/ q; O* J char strDst[]="c:\\temp\0";
. Z! ]+ ~: j3 ~! a$ M/ L //设置目的路径
; e- F2 T% Y- `; c& Z% m 4 [ X& T7 ^) W1 x2 [) \: X
char strTitle[]="File copying";
4 l4 W1 J( j* N H& X& V //进度题头
" P6 _& f$ ~* W: M# A5 K$ V6 V; G K4 X/ e5 r3 ?' N
SHFILEOPSTRUCT FileOp;
8 O: Y9 Q1 c2 T- ]; L& a* ^1 J! q " T; B: _. E, E' `2 e* H" S
FileOp.hwnd=m_hWnd; ( h8 x t, R$ ~ T
, t( x0 u( O: T FileOp.wFunc=FO_COPY; " S$ j5 B* A, H9 E5 o' p
. K) V6 e! P F- w8 O //执行文件拷贝 0 a0 A% k) s; d% y3 g: ]
0 o6 i( L+ i- p4 ~0 E* \ R$ ~2 @
FileOp.pFrom=strSrc;
+ N; W# E) }, x/ m! ] J* E4 t
& O- Q0 x2 G& C: v0 V. l' H FileOp.pTo=strDst; ; Y8 q0 p- ], H! R; g* M# A8 x" P
* c" U6 ~% b, w" w# X, c+ b. B$ y$ `
FileOp.fFlags=FOF_ALLOWUNDO; , O& v3 @, t$ k6 N
9 n/ y' O- _% P" P' |) ?4 R
FileOp.hNameMappings=NULL;
! H( Q& f8 }! U$ X4 _
7 f6 Y, G4 y) T. g FileOp.lpszProgressTitle=strTitle; 7 n' b' s9 r& s- O1 A
/ }1 e4 E8 I( M3 X; P0 S( X9 A nOk=SHFileOperation(&FileOp);
0 N" X/ U. u1 Z* c. u! V
6 |/ x; C6 ]) ^9 N if(nOk) # L% W# m) w! c6 y7 R, P; \
) |$ @7 M% x0 z( F! V+ ?6 Z; ` TRACE("There is an error: %d\n",nOk); & |; `) `2 r( |1 F6 `# F
/ v6 p) U' ?+ R2 Q else 0 R- F- H( Z8 @* X4 i4 R, {" m
4 o- T/ |2 V/ H4 a, I TRACE("SHFileOperation finished ( {% P8 s1 ` K) N/ g5 f
successfully\n");
1 F% Y ~: m9 {. Q) \! P1 P; s
) ?" r* h* R: F3 O# [ if(FileOp.fAnyOperationsAborted)
+ e. L0 x- ~: [ X+ Q 6 v* b \% g _ e* K1 d
TRACE("Operation was aborted!\n"); 6 h3 }! ?; P8 ^; u
}
2 w/ V p+ @; ?* \# P* F) g
- l! C8 ]3 T' [/ Z: J
# e2 ^$ D+ X% F三、 结束语 7 @- ?, x$ Q G! s& B3 }
/ Y6 Y$ h2 i' g5 a* b5 a I
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
7 U/ b1 _ S. t的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
; e) m: k' C9 L4 \6 r# \2 e, l; t系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 . E9 T) H* y% G
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 5 m8 n* j. J3 G
6 {) {8 S0 Y, |1 H- @$ K8 b5 S---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 # Q( J' V; q* @1 n4 c7 P3 h
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
! [" _- o d. L; a' [; G' A地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |