|
3 {$ Q3 ?/ L5 G, {3 S/ j
湖北工学院图书馆计算机室
Q1 P7 N' ~5 Z$ h. q' z- g& A张明武
+ [0 e( _) L4 t2 N
6 Y; o r% V ^; d---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 7 n( e/ h3 c2 T6 H# l$ \' _
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE 1 M! A9 Z+ B) ^$ z$ V7 _
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲 0 q" q! J) S3 R* t" u
区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 2 M: V) O$ \! j6 P, ~6 h% S2 {
库进行备份,很难达到最佳效果。 % P. h2 B: f( q4 H/ }9 i( ~
6 Q% A9 X, Q5 @( k2 Y/ R& M
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
6 c& Z" |; o0 P% V- D0 c' C现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 / }3 T' O4 }/ ]7 q) H; C! I
可以直接对一个目录或目录树进行操作。 " K' q) t8 @' B; u- ~7 f# e& T. N
! ?) o* W* r8 r) x9 {---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
; L" x; L) w8 i" X; K# b0 T文件的拷贝操作。
2 N( Z$ [& ~' m9 b, W a , O( v- P5 N1 ^' v
一、 原理与结构 % J/ @+ ]' H& C
* ]9 W p. K8 r* ? V0 r---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向
$ |4 ?% b: ]. y, USHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
3 k$ U& J* T( Y- n& r6 I t" P , v3 G/ k/ s0 h; k) W5 n' _
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
, `# w- ^$ p& E( H' ZlpFIleOp); 6 m+ z4 m: v+ E' m! |$ D* B
& K$ {- X. [- H---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
' O5 ]: C1 K2 |$ ]1 i下: ( U" G: m3 p4 u# k1 }, G+ x
( z" O1 {5 g, g& L4 k* K( @0 R Typedef struct _ShFILEOPSTRUCT {
; I- D& Y) _4 k9 h6 E/ A* ^ / y1 G+ E: Y2 C! N6 o
HWND hWnd; //消息窗口
4 \1 _1 b* L% S% w! _! o0 K 2 F" a7 c: a" h E/ p
UINT wFunc; //操作类型
6 Z5 j* Y. {0 V( L
3 j8 S1 Z" p* q: V LPCSTR pFrom; //源文件及路径 6 |. t/ E- G# F( }
) h( D3 p1 C7 j4 e% X$ V6 G
LPCSTR pTo; //目标文件及路径 $ B/ U+ T6 ^6 }* V
8 x) ]" p9 w# B6 I4 E3 o
FILEOP_FLAGS fFlags; //操作与确认标志 7 D0 h/ B$ D) ~8 ~3 I5 A# b
# {( l5 {9 t6 r& F; _' \! U BOOL fAnyOperationsAborted; //操作选择位 3 c) m0 B! n; R( ~+ G0 ?2 Y! ` q
: E9 V4 o$ @* t0 d' `
LPVOID hNameMappings; //文件映射 , t ?* \4 R( C3 h. t9 O, \
4 Z/ P/ H# K! g
LPCSTR lpszProgressTitle; //进度窗口标题
- |* p% b) P& I4 M6 b; u5 [2 f% t 0 S+ o, R9 l p( |
; r6 h5 g& v9 ^9 S \2 I2 H } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; + @/ [, {: H I2 e" p( J
; }9 ]. n' `$ V8 V: L' E 0 E4 Q! l1 p/ I# P4 J0 W( V8 o
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom - h" y. ]$ k' ~7 `
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 ) p: ^1 n3 `; N4 d4 u& B
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
4 W! @ o" i% W8 t( |9 ?个,则应是: ) h" x5 ?# ]- `( \
8 Z& Z2 Q0 D; D, R9 F
char pFrom[]="c:\\windows\\command
% m2 S1 z9 H' A- H ( r+ a% c4 p; W. a
\0c:\\dos\\himem.sys\0"
2 a( k* s4 r! u
: c% ~5 T: ^' m9 C---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
/ r( A4 Z8 W) h6 I; m进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 0 d% d, v4 m( x2 ^; c3 x1 Y
要成员,它指出将要进行的操作类型,是下面的操作类型之一: ; Q" d' ]3 ^! ?, D. Y7 J* B3 q( s
8 z; ^9 x& | {& R$ { ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
# k) B4 s$ [# H2 S" P+ h$ m/ z% E ) U" q: p- Y _3 V+ @+ w
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 % W; m! l5 b ~, M+ q# |
7 U" R9 x) S8 P: G8 H
6 a' G2 ^2 V) W
---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
! x. g& x, ]+ X4 R7 @. V6 t
/ Y7 R, [& @9 U1 B" m( X+ ^5 q ---- FO_DELETE: 删除pFrom指定的文件。 1 ` T% x: }: M; T5 u" n
/ a: F* E0 H- Y. Z! t$ i& H
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 8 K* b/ l* P, W/ y
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
' r; {+ B! u+ L移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 / f) k% s- f4 a( C) \
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 0 h: D3 v% W5 `' ~0 a0 N- V" T
组合。 # s: G7 y+ G+ V5 o/ F6 k# G4 w) j5 c
1 s* P" @1 W1 ~; f. G ---- FOF_FILESONLY:不执行通配符,只执行文件. $ I+ u8 O* x. v) C I
$ P( h8 p1 a, p) m3 X1 L3 ?
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. 6 J% r P# `* D$ \1 ?3 b, T4 s
3 Y, \9 z! n L& F ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
9 X# u; m* v- c: [$ `, x- W6 S; d h候,如
B2 k' a6 T6 C# j7 a, ?$ `7 s; x- h 果不设置此项,则它会出现确认是否覆盖的对话框,设置 7 W1 n% I4 k& n: T" W7 E+ h8 L
此项则
2 g, a5 \$ O) ?" f 自动确认,进行覆盖,不出现对话框。
: @6 a" P9 A2 h! l$ w3 Y 5 G7 v: U; G+ f9 P, i% l3 S
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
7 B% z: f \6 u n& `4 `现错误 0 v: {& S4 _& f- t" D
时,不出现错误提示,否则会进行错误提示。
) C" v: j" `: [) j# P. P
1 F7 I3 }& H! s( X9 @8 t* k ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 - V( k. N% _8 Y9 H% f9 @
进行更
7 X; L7 u0 ~0 ?# T" V 换文件名提示。
; r0 S1 P8 Q1 h& T8 |/ s
! h2 p9 p. i5 M3 @! g3 S" b ---- FOF_SILENT: 不显示进度对话框。
0 c4 b" N% w; b1 D- ~; p+ y
. {; ?* \. ^( x! @# h ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
" N' A# V ^' a7 \函数返
! y7 f" w: H- p* t2 l 回正处于操作状态的实际文件列表,文件列表名柄保存在
8 a/ K+ g0 P& Q" u1 F 7 [1 Z( J- B) r; J% [/ Q
hNameMappings成员中。SHFILEOPSTRUCT将包含一个
7 |: I; s% U: U0 r2 [ SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 # z% u% R. p* H; ?; R$ C
个处于
, ~& {) x$ v6 W$ H$ Q 操作状态的文件的新旧路径。 / q5 O8 y& u( ^/ ~9 r
! ? D7 h. B8 I; a3 Z
二、 实例操作 6 [: g- H0 p9 N6 }
" m4 A0 N- k- h7 J C
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档
1 _, p7 ]6 I( s, x* b8 ]界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
4 s- M! U, c* s P工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
+ T/ H5 Y4 M! m, Mcpp的OnCreate()成员函数中加入工具栏。
1 m0 u8 F8 Y6 K0 W3 G9 i( w/ ~3 i 0 a7 W$ Y5 o8 j- }+ c( E) A
if(!m_wndMyToolBar.Create(this)|| , e( p' e4 z, [8 g+ P
) V& u D( L8 t4 v; d2 T0 ~4 N2 V
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) ! ]1 l7 o& U+ T8 _
5 k0 J9 Y0 o2 Z; T; G$ _3 Y { $ Y$ j/ p/ P: e3 o- L5 Q
* m+ k7 v* x" P n# c
TRACE("can not create the FileToolBar!\n"); $ z1 r6 A; }2 E; x5 S! @
) [* q: q* q1 P1 W* x
4 ]- u o7 K. [7 q- v
return -1; : t2 W( K4 h; h C( y( Q) q/ a
9 f+ ~4 k* R. T
}
8 R* u& [2 v3 ]0 k: G& | % f1 z8 ]9 x" \- @1 W
6 b" \/ P* p. N: m. Z; g1 X! _---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
, u8 d9 |" X7 K, S( iID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
" j2 W3 Z: s& j% L& x- _
) N0 Y& V3 K/ @. p; h8 ?! P void OnFilecopy() ' i, i1 B& I6 H( D+ ]# o& U
{
9 g& r" Z. @1 {) ~; V S+ _% u) L int nOk;
" S( B4 g$ X9 M2 R4 E0 | char strSrc[]="c:\\dos\0c: 1 [4 K# U4 w' Y, S7 Z) L; C) k2 R
\\pwin98\\command\0";
9 b1 [! A/ E5 {% v //可以改变源路径 8 D0 k0 D8 h+ f: W' J# g
# \9 |* e7 c! e+ x char strDst[]="c:\\temp\0"; 9 q4 C+ @+ `; ~' V
//设置目的路径 $ h: W- t! H8 b# q2 w# N1 J- ~
& s& C* j5 \0 Q( T4 `
char strTitle[]="File copying"; 7 ^, k2 e* n% n# h0 i' b* t, b' e
//进度题头
& l- e% L1 r0 z7 W; A K9 Z
; M- n/ L& d! U B. K: E$ C9 E SHFILEOPSTRUCT FileOp; ( R' I! p/ k5 t" l! U
% N, v ~' F. ?; ^! B
FileOp.hwnd=m_hWnd; 3 w$ J9 P+ S! M# `
]" e6 d4 y' x0 D! u" \ FileOp.wFunc=FO_COPY;
# H- y! q: y1 S5 H$ C1 f ( X4 E8 J. p `' H1 L" j$ T0 P5 X
//执行文件拷贝 3 z9 l k |) _7 C9 G0 H
4 {' q8 t! J# a* F. F: P FileOp.pFrom=strSrc; + J! h) {7 r8 z! `, Y
7 g% l2 M+ b" O) B
FileOp.pTo=strDst; $ c& {! Y/ d* A* q, V1 P! ?0 }6 Z
& f8 x% i3 x" W7 E" X g
FileOp.fFlags=FOF_ALLOWUNDO;
1 ~/ [5 ^) q7 E h; b6 s: \ % ^* |* Q J! k: n9 Y( e
FileOp.hNameMappings=NULL; % g! O' R2 P/ V& Z9 @/ G
& x. b+ f7 ]: W FileOp.lpszProgressTitle=strTitle; g* r9 T1 G2 `
% r4 _* E2 H+ l5 e nOk=SHFileOperation(&FileOp); 4 s5 l% x6 P! n+ O
) V: `% ]7 Q4 ^; j' A M. O
if(nOk)
( S3 _+ e" y; h. g2 @# [/ q 8 k0 f8 {0 m6 z, M9 F/ ^
TRACE("There is an error: %d\n",nOk);
: l4 b; M' {" H) h! w6 C Z: D # f7 |. i2 P# m
else
8 N" ^" G& W9 z2 [, e( e9 L
7 l2 k l* w* H6 x TRACE("SHFileOperation finished
) ~' l5 j, X! h2 Psuccessfully\n");
2 C3 n9 F7 R) ]' } p5 P * x. Q3 J6 V9 o& j3 a8 u/ |) ^
if(FileOp.fAnyOperationsAborted) 3 d% N8 \* ^4 |$ [7 o
" U# |! Q9 U& [8 R TRACE("Operation was aborted!\n");
; M( C( r% `' n; o* y4 M3 T }
9 B5 C$ u1 ?2 S" i 1 s! U T, M7 X: V; f
( ^" b+ P. t5 S! A, X6 x0 U三、 结束语
* c! ~ }* t* e9 z2 B; _& b
8 M+ L8 a4 I, O9 p( G8 T/ p4 b---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 2 ?2 O: c: L6 K1 e/ p7 M& S/ U
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
! j( g, F) n1 l& P/ y系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 9 i; I/ \, ~+ {, |8 x( t3 [
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
* G2 e' U3 c6 p0 x, B M+ k! U2 ~$ O/ t/ g; G' j
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 ! Q: B$ P8 G" p2 Q
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
6 p+ a1 r! T+ Q; Z4 Z" x; Q地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |