|
3 t, J8 o/ ^, ]: x( i% Z) K4 @; Y/ T湖北工学院图书馆计算机室 & U( M5 J0 X+ f4 v6 Y( E2 ?
张明武 $ N0 N" N9 M+ P, A
, Y/ }4 `$ m2 C0 R, x" r: ] v---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
3 V) j: R& J3 \/ |- Z/ X2 R4 i9 ~+ @操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE 4 a2 m: T+ f! p0 G3 z' L1 `/ N
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲 7 x2 g, W% q4 `/ H
区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
& w5 e+ e9 ]) H; j2 E0 p( ` N库进行备份,很难达到最佳效果。
! M( ?$ @. F3 e- p# C 2 j" E0 h' S0 @- x) S) r1 m' B
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 ) f* u! K. j0 j: b' w
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 B( R& a) l# S/ T$ p( s8 f& J
可以直接对一个目录或目录树进行操作。
6 G- E$ R' r5 u8 m9 V( Q
5 p# c2 u* s. A7 M---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
" ~, l: Q) Y9 q$ E. h文件的拷贝操作。
2 ?; d' \- P6 e# _' o8 ? / j; M: V; u. B O! `; ?
一、 原理与结构 * V8 `2 o: I0 }
! b- Y/ h) Q6 { T1 W
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向
$ c4 S8 D& g2 iSHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
& d- d5 J9 C4 @# R/ E. `0 d$ V4 S- ]
: g9 |. i) D- }+ a1 G---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT ' ^" T/ I! J( Z7 |$ |9 e, D
lpFIleOp);
) i; R- I; n1 l' M6 x/ S. B, B( f
/ P% P% l' V, J0 x7 [---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 + t3 _6 K2 q9 y
下: ! W3 _8 b) l- T" d4 X! r0 \4 K
8 O+ b& g( }3 ~, M7 E. l Typedef struct _ShFILEOPSTRUCT { 2 S! i; d# A6 p9 L" }
! r- F" j# R2 Y9 u4 a) N
HWND hWnd; //消息窗口 , }; L1 i! k0 w4 L+ p8 I9 z
l6 m+ L1 y6 p, }% T
UINT wFunc; //操作类型
9 U/ L- {9 [4 S" N( e * |) x/ ?" K1 }7 c
LPCSTR pFrom; //源文件及路径 + g7 P7 H* G. Q2 }* A
$ @2 h! u; U! u) K2 K
LPCSTR pTo; //目标文件及路径 " ]7 a; g' f7 Q& n1 L$ Z$ u
$ Y; n: x7 ]' _- t FILEOP_FLAGS fFlags; //操作与确认标志
& o t" ^% }* V8 @" Y# S0 Y! L0 ~
% B: X5 P- Y1 Z; W BOOL fAnyOperationsAborted; //操作选择位
" p# j* `4 ?0 }3 M 3 y. m M$ Y$ ]
LPVOID hNameMappings; //文件映射
- n& I' d0 H, C: N) a- p 4 Y+ D! g3 q2 G' m& W) r
LPCSTR lpszProgressTitle; //进度窗口标题
( f: y( @& E' C8 {; d* v; Q 7 D( C; s# m6 T! G N
' @8 D% z' M( m' c! L0 L/ _ } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; / ]+ i7 c& y) P
1 o2 F. g+ h6 `) W: K * P& Z4 r/ t# L: R& G' j
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom - J% n) d: r, J G3 \8 N
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
# I) D0 F4 I G! k6 ^文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
/ u4 a! |: C- R9 O! @个,则应是:
+ T0 q0 A- O' M9 T$ P
# m/ F! f, S, ~+ R5 E char pFrom[]="c:\\windows\\command + J9 k9 J% S- V2 }8 H- r( ^" f' i
7 c/ k, D1 K/ \
\0c:\\dos\\himem.sys\0"
2 K) P; i8 n8 ^2 P/ M: l
7 w- E* r b. G( f" `1 r---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
7 I) P8 f# w( w5 `% Y3 I进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
; q. n6 r$ [; R0 |要成员,它指出将要进行的操作类型,是下面的操作类型之一: - c7 A4 s( u' u' ?
/ _+ c8 _+ p2 b$ l" Y$ T' _
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
6 o* E5 W5 E/ G* C8 n2 P r( m. }/ m3 o/ w6 q4 Y) U
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
, {- i: b- S$ R0 _% f ! x# e: n- x& `5 F! J. W
% \9 B4 E4 t) g& a9 }2 ^0 n8 C ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 . p7 R3 k- @& t
5 w9 A! G" E" H ---- FO_DELETE: 删除pFrom指定的文件。
% R7 \* X/ R8 l. ?* L' Y K - m4 l, v$ c" n. b
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 . ]9 G& K6 w2 u
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
) m" R$ \: x$ h* r" O. E3 N" u移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 , i1 |9 H; q* i+ s$ V2 O; ]1 R
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
$ w" ]- f- o0 B组合。
* g+ h% r* C& n; z $ y! |: b7 U8 J2 a7 }# [) f7 z
---- FOF_FILESONLY:不执行通配符,只执行文件.
, ^% j1 i( m) Y3 y/ f0 p% k6 E 6 C3 L9 ~; N' ~8 N6 R
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. " J3 F( {, Z- `" I! U
& b8 u2 r, {" A0 S. v( i$ e) N% ?( b ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
2 \ k, Q8 K: `' O. J候,如 + c- S; }2 i& a
果不设置此项,则它会出现确认是否覆盖的对话框,设置
0 [* _8 y! P% `此项则
0 N9 d, J2 l8 T/ @% b' a" y/ a0 m- ] 自动确认,进行覆盖,不出现对话框。 ' Q% f6 I6 S6 x4 P
$ C; o7 }' y7 G+ U8 q8 P i
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
3 u( K. q4 `# h( o5 v5 L现错误
0 ^ r) O0 |# t1 |- d! J) @) V 时,不出现错误提示,否则会进行错误提示。
2 L, U2 J0 r& Q! B' s9 I* H: a$ C 8 M. q; N4 t+ k2 l n; p
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 6 y% J, v+ b" Q( x6 B7 @
进行更 - {" y2 C8 _, w8 B# c: C
换文件名提示。 / Y! @) k% w# `8 N5 i3 N
6 L9 S7 _$ h/ t6 `( _. m
---- FOF_SILENT: 不显示进度对话框。 9 y6 v4 L! P% e4 m) Z# r
) S7 y. E: }. `3 B ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
/ j! G4 Q# A! Y% M1 q9 l' z7 X函数返
9 o% j: W7 R& x p2 B5 j1 U 回正处于操作状态的实际文件列表,文件列表名柄保存在 n$ B7 G0 P( b/ i* ?
0 w2 k8 R$ f$ P9 c- u2 l hNameMappings成员中。SHFILEOPSTRUCT将包含一个 ( z# w, U$ l- n3 L6 Q) b, c, v* P5 b
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
, w( s; k9 f6 [, [ `4 t$ J3 L# {- T个处于
f& m6 u& l4 @7 g: ]/ z 操作状态的文件的新旧路径。
6 Q" e1 d# ~5 \7 }5 E% v V" F1 ~- C% z% g
二、 实例操作
& ^( z. _ Z. t* A& e1 w : t; c, k5 y# _
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 - L/ T9 c2 O& s% E5 W4 Z
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
* J# Y' [% G7 d m8 V工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
1 ^8 i7 i! H ^0 Q% zcpp的OnCreate()成员函数中加入工具栏。 / w0 i- M2 H5 V9 k0 V4 l2 A5 O
[+ \% j- n9 `% M2 L
if(!m_wndMyToolBar.Create(this)|| % E4 O' y( E% l0 X2 I- B; w) x
0 h, y3 b+ h( a, j0 T1 M !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) # m( N; q2 j5 o, e" w
( W3 R( I4 D/ P' c. h/ ?5 L$ u, Z. _
{ 5 C3 J: B1 K1 m+ u5 o% h: v
5 s, l& E% d; P
TRACE("can not create the FileToolBar!\n"); 8 n; u3 `" h X# b: E- e
) u& H# l, z* G1 o% y . q$ L+ D6 Q' [- ^
return -1; 6 g! Q& D' H( I5 T0 l. O5 h" a
- X( t3 n4 g; _5 x$ ]2 T }
/ z2 N% D+ H) U2 Z- z
7 l2 E1 d! O3 F( a4 O
^. i5 ~) _7 A/ K1 u. q---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
$ I9 K0 F5 Q* U2 n3 p/ d9 O9 ]ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
$ h2 ]9 ?2 z9 {% X8 s / w% }! M& V/ O$ \* [6 p8 b" X
void OnFilecopy() k( O$ n! I: [- A3 g* K
{
$ ^& k! C5 j1 q/ L7 M int nOk;
5 U) f) f% r3 ^. C6 D char strSrc[]="c:\\dos\0c: 8 ~+ b s* M; \4 H' \
\\pwin98\\command\0"; ' F$ Z7 x; m$ v6 a
//可以改变源路径
! l" [. N9 |, y2 W0 l& } 9 L* s: O& b. {$ W2 C+ A C/ {
char strDst[]="c:\\temp\0";
* j) t G0 L. b6 E% ]2 c. j* G //设置目的路径
H& r e: n- Q9 \+ H2 r: q
- a$ B/ {' R5 N0 q1 T char strTitle[]="File copying";
2 M' c4 ~& J: c+ e) S1 X //进度题头 % L+ W5 A9 Q3 ^6 }' `
" s8 n# \& G/ ?& A4 {4 r6 f/ N3 k% Y SHFILEOPSTRUCT FileOp; 5 Y. k' u4 A( v y! ]5 F6 y( x3 L
3 ]& F) U% A0 c* d
FileOp.hwnd=m_hWnd; 2 J0 z( P# a6 E( G2 E& w" [
$ U4 Q- i2 b+ D
FileOp.wFunc=FO_COPY; ) y% `$ N- V& X' j
5 |* A/ ] C6 b+ R
//执行文件拷贝
- M( K" o6 T! y* X
: G; O2 }. v5 o$ t FileOp.pFrom=strSrc;
/ C! h- M1 \" z6 `3 |6 M; @0 e( A 5 D/ B+ r+ B8 m+ s& O
FileOp.pTo=strDst; : L, Y% A% `9 B7 W$ G) x
$ N8 E9 p2 W# q1 z+ l6 z
FileOp.fFlags=FOF_ALLOWUNDO; - Z, g7 ?; s, d# h y% W
. L% E/ [9 v% a. J/ `: F5 l
FileOp.hNameMappings=NULL;
5 f' {5 R$ ~7 n" t8 `2 I
& t2 w; y4 a s2 m& d FileOp.lpszProgressTitle=strTitle;
* F9 M- f! c; G: v4 D
( _; I; S* L# N/ B' G9 g% e nOk=SHFileOperation(&FileOp);
8 M5 e3 D8 K+ I7 E8 G6 a5 p$ N
]: F+ l1 U, O$ d) E! l if(nOk)
4 R4 X8 U& Y! E+ U6 x" i6 j
2 @( D- v' |# J2 S TRACE("There is an error: %d\n",nOk); ' p. \4 t. M2 G0 f: E7 E
! t7 y9 L3 r' ^6 F6 x
else
. U8 V+ C/ U: m' l2 l
$ q2 F) P, _( ?+ _1 K2 a% X- w6 p TRACE("SHFileOperation finished
' R7 Z e5 V. O8 Q, k& tsuccessfully\n");
9 E- L6 K) F( }1 w" a* Y$ `0 p $ G0 Q# G7 h8 H
if(FileOp.fAnyOperationsAborted)
' P1 e, Z% r* k7 i% e! u
. e' P) ?4 f- z J0 d7 r TRACE("Operation was aborted!\n");
0 k8 X* O& f: c6 R: g6 F S6 x }
( p; m9 q( ^* H( i4 a6 {
6 F* }& a# y# y* v: H/ h$ S- j" E : ~" s4 d& } F t: `: b( I
三、 结束语 ! s/ N& O" S& p3 |
" v( X2 G! B! n
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
* u* G! [ \3 ^的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
p( ], \. ^$ P) m系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 9 S$ t. Q. y7 l" \
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 6 N* U# H* ]+ d0 ~7 d
" A" U( q) f! Q" {
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
1 E$ d5 e) a7 W; y8 y( s2 o到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
* g) ]' Z3 i: U地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |