|
6 H/ D& X: a6 i' S, Y* \2 w( S9 t
湖北工学院图书馆计算机室
6 Y3 X" w0 n: Z- N$ R张明武
# m m! O9 S- o! c
) n% z6 t* L" x, O---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 9 i* B) ~* H7 [0 {* ~3 x
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE ; |. d8 J2 w/ n) j/ q+ X
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
" n' K% R4 y# [3 N+ f区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 , s# O% l: Q3 ^0 v: Q9 P2 S
库进行备份,很难达到最佳效果。
1 m. S9 l- M& k1 e . e% ^. j/ J/ K' f( s" @3 |
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
. @0 I1 c2 i! @2 V, C7 _; q现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
' ~/ k! E3 }- h可以直接对一个目录或目录树进行操作。
; Q o C3 x8 s/ |3 I6 c. j
. m' w1 F$ t& H# k---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
E7 ]- m ~7 d5 e文件的拷贝操作。
[2 u7 s* c/ f
; B- O# r9 k( \8 l一、 原理与结构
7 [" R* I/ d4 y
( r& E. B1 W$ P( A1 k% } t+ L---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向
' T# z. d' r3 `/ d4 d: QSHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
( K# M! k, Y8 I6 d' W$ ]/ t
5 e5 T0 ~( O1 f) q---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
6 r$ t; {1 \% R5 x4 z/ D2 vlpFIleOp);
! F# K$ S. p2 z5 c) C0 n3 Z & k. M% {( h* e4 R e U
---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
% F# o F1 t- S$ I下: ; {. ]1 k3 k3 E. ?/ X. I( O% A2 g: M
% Q# o6 g' o& \/ X Typedef struct _ShFILEOPSTRUCT { % o: p' A0 @. [8 r
$ j- z, `3 _9 f0 C HWND hWnd; //消息窗口 5 v; m: }9 M9 o- X
1 D1 n( b& h4 Z$ y- c4 n/ I0 h UINT wFunc; //操作类型
4 x7 k- @& A n+ k 9 M$ c) n, L8 q7 _9 D3 j: [* s
LPCSTR pFrom; //源文件及路径 2 z, p( J c" g
, a @8 W% j! s% E
LPCSTR pTo; //目标文件及路径
9 \ S( s, J6 G3 `" j+ l+ q" V
% g6 k( w; l. O0 |) O1 j- c FILEOP_FLAGS fFlags; //操作与确认标志 e7 r0 ~6 F9 \) a. A$ k, \6 d& J* ^
7 R0 b$ r9 C D! F4 f$ B BOOL fAnyOperationsAborted; //操作选择位
: ~, v) L8 ?0 d6 v/ ^ . V+ F, z7 ~# M I
LPVOID hNameMappings; //文件映射 Y4 P/ ^9 v3 F6 X0 o
) u, b4 m: Q# [1 p' Y1 U
LPCSTR lpszProgressTitle; //进度窗口标题 9 R0 |+ v7 F5 ?- l& N! G. x
; A! u- A6 q8 M# }. n8 j$ \ a* O# \( ], h8 t t, L: C& n
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; : `( H4 i9 u! u9 s E5 }8 E/ r
+ o+ F- K8 |& E+ V, Q# m' F * C- l. W- g9 `/ Y. C! i; X
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom , l% j; a" E; c; F
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
) U3 \; ~, Y, [2 z文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
$ k, e0 B$ o/ p# x# O# D个,则应是: " ~7 E7 h ^% T7 w6 L( \: w
, @- z1 E9 S6 ^9 B9 G char pFrom[]="c:\\windows\\command
4 v' K$ j, F- f K H( d5 J2 g
5 b* \( p3 B! _6 ^6 t" ` \0c:\\dos\\himem.sys\0" , @4 t' @, m: D" a3 r
6 K# ], Y5 j8 p
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
- ]" F( }9 N* E7 ]9 A+ e, @进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 # T6 x+ Y6 D& m( W# _) ] Z; y
要成员,它指出将要进行的操作类型,是下面的操作类型之一:
; R7 }0 M. J2 f; n" A+ i/ w! t
" c; w. ]3 [& T! d ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 ' ]4 n2 m9 _7 i6 a( j4 p1 U: m# a
7 d9 `0 O9 x1 {" w
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 7 h9 C% h; B3 o8 Y$ o7 W8 S& P
0 @" Q3 p% c8 c' w- ^- P# t
# z" X9 a9 g8 u# A8 Z ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 , \3 e: o# F2 H
5 c/ U2 D3 q+ x3 M- v- B: `
---- FO_DELETE: 删除pFrom指定的文件。 M7 H, e5 U! a
' F# ~( s2 h7 q( ?, V2 A---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
4 Y( l$ @8 U3 I; S# b+ s0 O程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 O8 |6 }& u2 @! z1 Q
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
+ G! I: R( W9 f2 p在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
5 i; k3 L4 Y# T9 l) e& s组合。
# c# W6 }2 c5 Q# \7 H2 Z. Q ( P* A( ?# d5 e& V
---- FOF_FILESONLY:不执行通配符,只执行文件. 1 h2 _& O/ b3 Z, f$ j
4 c: {% |2 T" @0 `
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
% k9 V! l$ b8 W
2 Y6 p, p; W: ?* Z& o% \6 ? ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 4 @& j/ a _1 s6 J
候,如
0 z7 Q% w7 Q) O4 G, T6 ] 果不设置此项,则它会出现确认是否覆盖的对话框,设置 . H7 R9 o" z% V- q4 Z# D
此项则
; g1 w" Y- D8 H 自动确认,进行覆盖,不出现对话框。 6 P0 |% z4 G+ N7 b6 I$ |
3 r( f; d5 b$ E: T% h ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
1 V( r) `4 m7 s+ c" E现错误 9 m0 o+ |6 L5 v3 ]
时,不出现错误提示,否则会进行错误提示。 ) g5 t% | {" _( J ~- \( P! Q
# G# h0 K) R0 O: O' b% p. d$ F ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
5 d$ q1 R0 u/ ?6 G进行更
8 b/ v! ~ r; b9 } 换文件名提示。
% S+ \6 V, D, h/ i5 p1 D- Y& A
6 `! r! J) Y k9 d7 D1 m# E- ]" H/ c ---- FOF_SILENT: 不显示进度对话框。 8 R' L+ E0 U' k8 [
3 ?# u" z1 n: O0 U
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() 7 Q2 U6 q: \" I# I4 ?. z
函数返 ! f- ?$ q7 D( \" N/ x
回正处于操作状态的实际文件列表,文件列表名柄保存在 # q7 J! M* u# {$ P, l
; O3 X1 b8 _' t! d, { hNameMappings成员中。SHFILEOPSTRUCT将包含一个
; T( y/ \0 p" a& j; k7 D, v# Q SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
" J! L2 _- O4 U9 ~" N) i) W$ k个处于 3 b6 f0 i& T3 H
操作状态的文件的新旧路径。
' S3 q# H8 t- n4 v- H) P : K7 {2 L N' U- z3 Y# a
二、 实例操作 & J: i. u% `7 d' Z; }2 w
% D6 G+ `! h# m4 _- D# ?7 c
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 ( y4 X9 [2 f; |. M& }5 d* i
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
: s3 A1 f9 n3 Y6 z工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. - r1 x2 m" M3 w9 L
cpp的OnCreate()成员函数中加入工具栏。 3 l U3 h$ g; o' d6 R
7 A$ `& t/ U% k( [
if(!m_wndMyToolBar.Create(this)||
! E; M- j6 o$ D
4 l. O, D8 Q6 B5 d2 q0 @ !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) ; ? x0 b( d9 M( w- [
; ^% c' Y k* h. m, ^7 g( \
{ 2 E' T, \6 o7 h2 t0 I
' X, U; C. p! Q
TRACE("can not create the FileToolBar!\n");
% f- ^) v9 y0 F# @; G0 \9 o
0 y5 E3 B- g5 l0 D. E8 i B
% y7 D. f0 J2 O% Z t* Q; G return -1; 5 ~) C0 u" W9 ?6 A- n
- o [" }; H6 _% C
} ( @7 H7 f2 i% ^# s1 C( R: n/ f" O
# q, K) [& P1 W0 t9 L
( B( ], r- Q0 D& E# J" p---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
" Z$ M3 M& @, I, r; qID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
1 i; g, S8 @# H( E2 y$ c4 S
# E" t# w0 j- ]( n void OnFilecopy()
( m* o- ?. @" n1 J9 C, ]9 H { ' b/ Y+ E6 o& Q5 t1 y3 |3 }! s
int nOk;
0 n; F/ t* J" H1 w0 M char strSrc[]="c:\\dos\0c:
% s6 Q5 K7 H9 s\\pwin98\\command\0"; 6 Q# @& T1 ~/ p- o: I
//可以改变源路径
9 d+ I! e4 l; P6 ` I 9 M' y5 o. \5 G* O, ^9 K/ n
char strDst[]="c:\\temp\0";
8 C* r- {, u5 D //设置目的路径
) i0 Y1 ]& |# Y. v) Q* A
8 ?* {3 b; y; y: E5 r9 v: z! Z! k; ~ char strTitle[]="File copying";
0 h1 O' p2 a% R //进度题头 # |: `- b4 O% Q: O# g, {
! ?' k( ]5 c( b4 {# l) f SHFILEOPSTRUCT FileOp; 8 n; U3 ]: M; U: X
2 ?9 c4 o2 ` u
FileOp.hwnd=m_hWnd;
$ C3 c# a" E, I- F( L! Y f % C% H2 O; q8 o! ?0 {" w7 q
FileOp.wFunc=FO_COPY; # E7 s) B" d7 V: Y5 ?
4 v8 I/ p2 A3 H5 @ //执行文件拷贝 ; w( H4 x* L8 r; t( e
, }3 I0 w& \# d: Z, o: W FileOp.pFrom=strSrc;
1 s& W& i/ y m) {/ M6 [$ I
$ F, `2 G" a; H9 ~ FileOp.pTo=strDst; 9 M; u( F2 O. T
z1 k8 t# S8 e, M0 L! c
FileOp.fFlags=FOF_ALLOWUNDO;
, o1 E/ C1 k1 S+ N3 b 8 @. o9 ?) V& T+ W7 b7 n
FileOp.hNameMappings=NULL;
& U" t* w+ ~) N; P( b/ s, y/ U
3 e! M2 n1 g2 L6 m3 [ FileOp.lpszProgressTitle=strTitle; , w& n4 E8 Z9 F
3 x [/ x; i% V. A nOk=SHFileOperation(&FileOp); 1 j3 H. C3 f7 U/ t
8 h* Q' H# k+ i3 y) r
if(nOk)
! H$ T6 \3 J5 ?7 n
% O8 C: i) c! L* @- N TRACE("There is an error: %d\n",nOk); : D5 ~/ y( W4 X5 S# ^5 q5 P
6 V, @0 Y" e0 r/ i* c! V
else h3 I% X; y5 w8 b* K
% k! u9 I8 c. T7 e2 v) V
TRACE("SHFileOperation finished 1 M& I3 Y. s0 q7 }7 B, x0 }
successfully\n");
B5 L- f. L, E/ N3 G' x & c9 `0 i6 A, x* r( L
if(FileOp.fAnyOperationsAborted)
, N5 y7 L# d' }3 c
0 a) ^7 g2 _% H. k TRACE("Operation was aborted!\n");
p9 Z$ W: H0 k, R( j2 ^ } 6 W& s4 H( I, I7 h
0 | W6 ^' b7 W
5 T; H; r# R+ w+ f+ d# o2 ~5 M三、 结束语 # B, f0 K( P4 k) F$ G# L8 ?% E
$ f/ F" P; C4 s% H---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
" E+ t$ v6 U/ H$ S; ?的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
9 O- ^, |6 d1 m& g, O# A* o7 |" a系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 2 `8 x2 q/ H3 ?
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 $ ?* |4 a3 |8 v* g1 M( b
* [6 M. d! ?& i J/ \0 E/ f3 F
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
' \4 _0 z( G* e到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 . G) z+ M8 G+ z
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |