|
) b) L) V V, b; P O! u7 q3 ?湖北工学院图书馆计算机室
7 I6 y3 k9 d5 {1 ^' U3 S张明武
8 l( O" L; H% s9 H4 } ; H/ n' t* A& B
---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
+ v$ w& F! J+ Y5 X( c操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
& t( `6 p6 U) ^、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲 . r5 W' K* j/ U' b8 D! b M
区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 % p0 C; A7 u# l7 \: |; N; X
库进行备份,很难达到最佳效果。 4 }9 y( {8 U t' b
. K/ V* `$ \8 b* G' i2 }, `+ |# A- @
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
& V) q' d" h3 \2 v* j现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
7 W' f4 l. p5 d$ ?+ ?' a可以直接对一个目录或目录树进行操作。
% ?5 V" I% O X
$ g* m/ s6 F* N; j---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
, [' j S+ {6 S5 r; w文件的拷贝操作。
2 D! \7 k3 ?5 a$ F% ~9 w
9 T. K0 p1 z# i* {- S一、 原理与结构 3 X+ t6 a) l3 K& l" s P w5 B
% y0 c& d6 I! [. B. g. y
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 8 P! K5 x z; n; C5 S- {* ^+ x
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下: ) m6 V) }3 p2 _" X. V
9 o% A% p2 `) N* u. b+ @* O/ ]
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT q: @1 E* P4 l
lpFIleOp);
- t5 i" P7 l. b% Z! l$ V) q 8 A5 T- f; F/ C5 E' l8 D# o, r
---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
+ {- y- V5 f0 t6 s9 h' Y下:
2 v6 k) v- T5 n) K, ^, i( d3 @; f
$ J3 T2 W' S& Q. p Typedef struct _ShFILEOPSTRUCT {
) {7 J3 t' q. R0 ?# m3 G
5 w4 n9 }6 D0 S& l0 D- J HWND hWnd; //消息窗口
7 c! h# W% B5 t% e/ S( f5 E 3 t0 U# y! B) o# j+ k0 S8 ]3 p
UINT wFunc; //操作类型 % N1 s; J( U* L5 R5 @2 f
4 `% q6 Y& H. J4 v' J LPCSTR pFrom; //源文件及路径
4 n! ?. p% d. d; S3 N
. D' P$ `5 ]1 s1 a0 n$ u LPCSTR pTo; //目标文件及路径 ! Z' o* X; X1 }- y3 T/ w
# _( f/ ]5 \3 X8 o FILEOP_FLAGS fFlags; //操作与确认标志 + l( R; B" }; g8 ~
: D$ H; s6 u i" M) q. f( M BOOL fAnyOperationsAborted; //操作选择位 ' U3 a1 t% M& k2 u: _$ M
0 g4 a$ A& p( \+ @ LPVOID hNameMappings; //文件映射
: p" K2 S+ W7 m8 T3 v! X
0 x$ ?- E# \; B0 ^ L LPCSTR lpszProgressTitle; //进度窗口标题
! P( [- l3 B$ r x
. ]! m$ W) n# { X* G9 j / J0 L/ B [; l8 |; A
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
! S$ ~9 D: g1 t1 c* r- S. t
2 P d1 q, r ]( y9 i0 @* y' @+ _ $ j4 `. j) I% {" G, o5 ^
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom ! r6 n$ e0 ~5 \ {! W4 l
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 3 Y5 B* o6 t9 h: [2 g" @
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
9 e+ C0 W* y, e个,则应是:
+ s5 ^2 v1 B3 \7 C* V% \. ~
3 r$ a j5 @8 @+ x char pFrom[]="c:\\windows\\command
2 o. O* `& f8 ~8 j
- ~: G* _+ `" G1 j6 _! ?* r5 D \0c:\\dos\\himem.sys\0"
3 u/ y8 I, m Q: v, }& f
0 s5 w6 ^. M6 q, B---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
% T: H% e/ D9 Y& V进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 " ?- Y4 J, d1 }
要成员,它指出将要进行的操作类型,是下面的操作类型之一:
- F( T& O4 o% l" U7 _
. H' _8 D* a2 U: C. G" Y, S4 r ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 / q0 Z+ d1 q5 ]0 t2 w
0 `' L' g6 C7 E) B* L% S( ]5 y" } ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 * o) O' b& U# ?+ ^ A4 H
9 F9 u2 E- U9 z# U Y5 L, c9 A
/ \/ I L7 O) |7 I/ D" [9 V ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 & x$ A% I% m* }: @2 n* k7 b( E) N* i
( o9 M& C" E) k1 ^! {! ?( q ---- FO_DELETE: 删除pFrom指定的文件。
I# P' T" G5 [& E' M ! I% P8 O* _# |; v+ e+ f' m/ N
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
& b8 B+ A" V- t9 }程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
: S/ A @9 a) @. \9 {移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
3 n# O" `% ~3 Z; }4 M9 Z6 U: _6 O在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
8 b9 e7 W5 F7 [ O组合。
& \% V: x( O0 _* ^1 B( I + n5 C! v" \/ f/ k
---- FOF_FILESONLY:不执行通配符,只执行文件. w& u" v s M# K3 R( S
( S- d$ y4 s+ y
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
- W$ r( w* c( L& U0 c
7 X% m) j% S2 \- Z2 Q ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
+ n8 F7 \: R6 G) e( z4 R候,如
/ W& ~9 X$ Q" O 果不设置此项,则它会出现确认是否覆盖的对话框,设置 - H' c8 P: B1 |- `7 D: x
此项则
; _) j& }; j$ b, E 自动确认,进行覆盖,不出现对话框。 ) [6 g9 Y7 ~: u& y5 p
( `+ s' |. M" k, u
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
( C% r3 F; M# j现错误
1 X$ X9 ?; }. E# T( S4 z 时,不出现错误提示,否则会进行错误提示。
: Q, H$ R6 h3 M; b1 i9 k : D1 D4 I/ g6 @1 `+ O
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 7 x' {: q8 B9 Y& Y6 D. N
进行更 # p# U; M* ^. D/ y- r& Z; o
换文件名提示。 ' d8 ~: W( b6 s1 {
+ i4 j+ ]3 C! C! u5 g1 a2 w ---- FOF_SILENT: 不显示进度对话框。 ) T* o5 h2 J& ~( t! Z2 I# ~
6 `$ c9 S$ s5 b4 r ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
2 |" ~! D3 }! X2 b. Q' @* I函数返
* ]4 W9 ]$ q6 l& h3 `$ F 回正处于操作状态的实际文件列表,文件列表名柄保存在 ! J% _) t3 D6 W: g+ I( i% b
$ d H/ V8 |$ F6 Z: P) Q
hNameMappings成员中。SHFILEOPSTRUCT将包含一个
5 r/ ~4 N1 O, c SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 + A( S% j- {! q# F3 ]$ n! g: {
个处于
- [* K0 ^( w( \ Y, K 操作状态的文件的新旧路径。 - A) w, p B9 x2 C
5 B. ?( T) u& x0 D1 y二、 实例操作
9 U2 B( U; m4 V4 h ! g: p+ n% N, @2 m8 P' }
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 : ^- U' c" v& C. u0 ~3 R
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个 & R4 r3 `' o2 W) T$ U2 e W2 P6 q
工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
3 m2 B4 C1 o9 V/ n6 Ycpp的OnCreate()成员函数中加入工具栏。
) ?' x) z& O" P. r8 D$ V Z * x) t' T* d; Z8 F6 w* S
if(!m_wndMyToolBar.Create(this)|| ) |; }5 l4 W8 H# G) r! u' b+ F! G, L) r
# f& Q. D& I5 U! E9 w. E
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) 5 n5 ^# l! W+ N6 o) Q
' B0 ?3 V1 Q7 Y! h' ?" V
{
& Y, T+ c+ S. R& f& j 5 J4 l: ?4 E) E( p
TRACE("can not create the FileToolBar!\n");
% C" A; Y" k- S % H `' g R6 [0 S! _
2 x* M! i( U$ a0 X+ L5 S% [
return -1;
! [1 f6 A2 m" y" ?4 ]9 U* f 3 S* R/ P7 u- ?" \* e8 {
}
0 x: ]/ |! i& G9 r- ~$ T # z- g1 O* V/ m
7 { Z7 B* p$ h2 l---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
F' h7 [2 k. H+ V+ [0 x2 \* [1 ]ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
' p7 O k& t5 j, _& B 5 M# e h% p6 M9 k: v
void OnFilecopy() $ U. y! F: n6 d7 ?7 [' g5 b7 g) {
{ : r( T. ^' |4 Z5 }8 ?9 O% \
int nOk;
- O' P# B) a( h- \$ Z4 Q; L4 f5 S char strSrc[]="c:\\dos\0c: + ^ P. g; k5 g" q9 J, \ G
\\pwin98\\command\0"; " F' a8 Z2 x- t4 [* B: m
//可以改变源路径
M0 l' B* O; I1 |" l( ^ * n+ E2 D/ R; ]- d; x
char strDst[]="c:\\temp\0"; 9 `6 |# \7 N3 L
//设置目的路径 & ?3 ` X; X1 S0 `- v+ L: j3 |4 `
+ y5 z" [- Q8 w8 \1 p4 ^: `
char strTitle[]="File copying"; 3 ^7 \% B$ v4 f) U- Y# s' I0 L+ {- A
//进度题头 7 W9 w' N4 Q, ^
7 E0 [! u# Y/ u9 g3 ]" q. k' P SHFILEOPSTRUCT FileOp;
# c% s1 |% W0 P6 F6 {! T/ R/ R
5 i* Z" g9 H, ?7 h9 @ N9 {/ f( V FileOp.hwnd=m_hWnd;
( z: T \! b3 W$ y0 m' i % Y# C- c, @0 j$ M+ A/ O
FileOp.wFunc=FO_COPY;
. T* r3 v5 U3 Z- ^4 S
H' p' I7 | ]5 a% h //执行文件拷贝
1 s) U4 k/ M$ R- P1 s! y7 u [
; ]. ]4 g F7 y; g5 x FileOp.pFrom=strSrc;
( E& V# a& i5 W9 L/ f% G% q
$ D" S0 S2 l( ]- Y* H FileOp.pTo=strDst; 7 q0 e5 c- I" T$ O4 z
% x5 q6 F' }; a2 Q FileOp.fFlags=FOF_ALLOWUNDO;
( Q' c, D- B! t0 W5 K+ F+ T * ~2 f' |1 V9 d& k6 a
FileOp.hNameMappings=NULL; $ u. L- r/ a2 X1 V9 e
9 t% y! v2 s1 ^6 X5 m+ c) y$ g# C/ q
FileOp.lpszProgressTitle=strTitle;
+ A6 u% G- d$ ^( N" [: _/ t: E) v
- I5 b, R# ?, C, v9 d& D8 h nOk=SHFileOperation(&FileOp);
8 ?% `6 y* q5 `, I6 n
]3 c0 a/ G- x: }: a' e if(nOk)
) O7 g& p" O4 G' G7 e% S, C j+ Y
, o% a. n. R) m9 I TRACE("There is an error: %d\n",nOk); " P" X% X; O, Q0 ]6 }3 O" ^
1 L+ V3 a2 y# } else
# s% v, }9 J/ C% I# H ) r6 M& w" f# r, g. ?- K
TRACE("SHFileOperation finished % F- W! J( v) G7 n
successfully\n");
2 D4 ~$ N/ s/ w8 A4 l* s
4 J/ d) l" v. s! m7 u8 {$ C' D" a if(FileOp.fAnyOperationsAborted) # B/ _: L' b) U" i/ W
. j" W( z- o2 q$ ^) h( w2 F- f
TRACE("Operation was aborted!\n"); ) }2 k8 r# m H
}
3 O0 Z+ X5 U# t8 o2 } }. g / {2 g& ?3 E8 I( p; t1 w7 t
8 s; a. z- `7 ]/ W# i1 P [& X
三、 结束语
* f6 Y- i1 u; B1 f& Z8 b9 w1 _
+ ]* Q X- l0 H/ [3 V/ w5 Z---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 ) J2 s, @4 V4 x q9 Z f( Y- b
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 . W1 F- j0 }9 h& E+ ]
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调
) w, ^+ A" P! H1 p1 o; _( b% n用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 * Y8 G& }5 }7 R- P; }, b6 _
5 u4 F/ u7 V; C/ h# R0 c0 H---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 9 a0 X; }4 s! ?) R1 v( ^$ P
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 6 ]0 E' }7 K' z( ]/ P5 A
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |