|
d% A$ m# E# `6 G
湖北工学院图书馆计算机室
" M" x' Q, V, I! x4 f& c5 @3 ?9 } O( e张明武
' _: B2 C0 z( \' j
+ x) `9 @* ~7 `( V( j; s/ y7 S* j, D---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 ) Y Y( E# q3 u! r& ^3 O# ]
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
9 k- k3 @* m/ Y# X8 R# o2 H、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
9 ~ S9 q# p' |) F! e" L9 i* [! I区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 7 ~! y5 Y5 q$ I& H
库进行备份,很难达到最佳效果。 6 @+ i7 i- Y: H
+ g" ~) `- v7 w }1 a8 p
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
9 N" m p7 j) s9 Z9 v4 N现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 % }! _+ e* W% X
可以直接对一个目录或目录树进行操作。
& |. P; h4 i/ p* G
7 V: ?' W' J+ p. c) Z1 _3 {---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 $ ~* X$ ?3 T8 { C1 ]
文件的拷贝操作。
8 A9 R ^9 w- Y# X! _4 Q$ h " G1 {9 v) R% r2 {. `, V4 p
一、 原理与结构 5 T' m1 [; g4 T, \. O, V- m' k. i
. b* j# ~2 Y/ X' p2 L. A/ N# D---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 2 ]) I9 q) D+ S; G; Y( y! Q
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
' j3 q9 R: ^1 R8 k, @$ w
2 d1 V+ y: H- n4 r' z2 x---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
5 K. i3 v) z MlpFIleOp);
6 c! ]4 d4 }( g+ g" ]
. v1 W$ e- M! X: h" n+ ]; U. P---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
9 T5 _4 V; F0 f* A下: ! `3 B( L. q: o- C! {! E" {8 K
0 V8 J* z" `% @* l. s) e Typedef struct _ShFILEOPSTRUCT {
8 _! V1 m( A h3 D
2 i1 u: L$ l+ K5 r% C3 |- Y HWND hWnd; //消息窗口 ' }' G/ _& k5 }+ r1 ^( k& y
( o; T, j% S4 X
UINT wFunc; //操作类型
5 U" l2 U5 M* e0 e 7 p- g7 ~5 g, x" N: I
LPCSTR pFrom; //源文件及路径 ( N. U. {# f! |# C, R
+ _+ q$ s7 v" u* X LPCSTR pTo; //目标文件及路径 ; R1 l0 e1 i9 }3 [- F- \
7 V" v% h9 J" I6 t( O/ f. L/ v FILEOP_FLAGS fFlags; //操作与确认标志
d$ t" L& }5 L5 B3 m 0 T1 B4 @, a# u& R
BOOL fAnyOperationsAborted; //操作选择位
9 ^3 ?- K$ E0 k$ w' v6 H" N0 j 9 j x2 B5 o9 J \9 p: Q7 B# @
LPVOID hNameMappings; //文件映射 7 p* I! S9 d$ @6 ]5 M3 C- Q) k p u
/ {5 r6 x/ s; _. [: g3 R
LPCSTR lpszProgressTitle; //进度窗口标题 7 l, m( q/ U2 R
$ a0 G( e9 b. ^; Y
; o/ h8 k+ H2 {
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; $ N" P/ ]. \' V" Q' @
: P# E; Z5 W0 i
: T, |- U' i7 L0 j
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 9 Z" G. [7 ]2 s& [! l9 _5 j5 N
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 9 [6 Y5 H$ @& Q# h0 q& G! |# I
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
7 Q1 Y1 X, d& w0 T2 C% e3 D. C个,则应是:
6 y* f+ q+ J* A9 \ 0 f" q& B# a. |6 @6 w$ |1 R b! g
char pFrom[]="c:\\windows\\command
% K2 z+ ~) Q) A1 t7 P8 [
a- n; D r4 q$ o; b \0c:\\dos\\himem.sys\0"
8 Y- f: ~ \: c* {4 d, X" c % ^& n0 c) v5 q8 h% @5 f/ k
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 8 m+ W$ G/ d* y
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
& W% O) v4 |; L. x0 Q3 I' J8 x8 Z要成员,它指出将要进行的操作类型,是下面的操作类型之一: + _' [1 R6 o7 w3 ^
6 o$ {/ B: f6 k$ R* F2 y" b: d
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
6 j. ?. E/ j {1 a* J8 k' c
9 G3 [$ A9 N! I, w0 V ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
$ v. s' k( C3 X7 Z# M# B ! H) q6 O* a3 z0 U+ I' P) [
2 O. C" F) \# y% c# t" } ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
1 H- [' c d$ K9 L& ]* e7 N0 F
- j: j e- | E ---- FO_DELETE: 删除pFrom指定的文件。 / X6 c6 M8 R! m5 }3 y, c4 C/ Z5 p" T
! G, m+ L% `6 M- Y; o8 Q! x9 t
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
8 c# n% [) f5 J* l程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 ' d N0 o+ R9 W: I- h, F
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 9 B$ B3 m& s% c7 h) _" Q: q0 h C
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
' y. a1 V+ N k: c2 k2 G组合。
& Q8 n% @# t! k% I2 [4 g 7 V/ p; c! h; N0 I5 D8 r
---- FOF_FILESONLY:不执行通配符,只执行文件.
; Q8 |1 [' o' @: q* C1 w ) w$ t* K0 ^2 k' ~* A1 ^ v6 Z8 \1 ~
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
3 x3 }$ z4 l& X: y, y7 A1 _* h2 J 1 Y7 {/ w6 {4 _7 h
---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
S j" U4 u! K6 w9 o候,如 $ i* u3 g* L/ {8 l! L8 U7 f6 d
果不设置此项,则它会出现确认是否覆盖的对话框,设置
" f2 f* u5 \: p2 T- O% d" H D此项则
6 V% w$ ]. P* n" ^7 c: q 自动确认,进行覆盖,不出现对话框。
; c, W1 G: y2 c) I9 L* y
$ A* i! P6 \; g3 A. V8 Y/ o ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出 * E$ ~7 V+ k+ o# ]. n$ `
现错误
/ d% H! g+ c) H5 }7 ]; W 时,不出现错误提示,否则会进行错误提示。 / i3 D, [4 X( W
) ]( s5 e+ z, E5 C8 w
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
* @ y5 N; p. v, U# Z3 m g进行更
0 [- g+ t9 R/ {: K' |* S6 \ 换文件名提示。
* E3 ~5 W: w$ O) O) u& ~/ A Z) i- B 0 c7 k" M1 o5 D& }% @
---- FOF_SILENT: 不显示进度对话框。 ) B: c* l; y2 u6 K# |, m& _
! S: _/ R( r6 g+ A: I7 F0 e
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() . \- a( v3 |7 A, T1 m
函数返 G% S0 s. D% b
回正处于操作状态的实际文件列表,文件列表名柄保存在 * [. G# u* Z) k5 M7 U' _
- j8 u0 Z# w. z' t* }/ F hNameMappings成员中。SHFILEOPSTRUCT将包含一个
% e3 E3 `1 @8 `: T9 `5 ^6 [5 H SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 9 @0 G+ y* o) c
个处于 m0 d m& u5 N2 |7 a+ R4 Q. N
操作状态的文件的新旧路径。 ; j D8 M4 z; @3 }
6 Z- u& |, z1 I: t: @9 V0 N
二、 实例操作
4 ] P3 g" t9 I! K* D 4 y3 O; `( F8 M8 I- _: a6 Y
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 ; e- Y$ w1 s9 _) ~4 s
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
3 B$ L2 [- u$ b `2 h% Y工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
- N$ r4 w' M( `cpp的OnCreate()成员函数中加入工具栏。
X9 U; K3 o# H" f% Y( V 1 f5 c4 f! d( y5 M( V7 l9 |
if(!m_wndMyToolBar.Create(this)|| ' G: f9 j0 \+ A; D
% `* E6 ]* \! k v8 o3 K !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
9 ^8 I" L: W2 w3 a# `& a 3 X: |( o# M a7 P8 U
{ - [5 u. k" s9 K
, c8 ?+ F3 p3 P. l" `2 }# U TRACE("can not create the FileToolBar!\n");
% E- | m4 C1 Q4 u g2 |
; Z, K8 y% K/ S ' e& _! V( C7 ]2 z, f$ s
return -1; 9 A4 K3 p2 t- D2 w( R* F
' T+ T# V2 j1 Z v4 B
} , h. a$ l: L7 W9 ]/ t7 ?' t6 l
0 W9 W$ z- Y# r5 j; ]$ w
) h5 ]5 S5 ^! }6 H0 |8 ~---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息 6 E* R$ n5 z. |3 m7 M
ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 : l e0 a! ~8 l) C S' l& }& v
# f: H; e/ s; u# g: R7 \3 q: C
void OnFilecopy() ( B u/ Y- s. ~8 i- X2 |
{ 2 }# W+ V4 O. b5 {5 V% T
int nOk;
- _: V* p5 H6 s5 E: I9 [# j char strSrc[]="c:\\dos\0c: # m8 h* a( [* C& L1 g+ y
\\pwin98\\command\0"; . n0 u" V: h" B$ K' E$ u( e
//可以改变源路径
5 E+ d! m5 M3 R! H& m# Z1 X 6 h/ B& X4 n i# s1 P$ F
char strDst[]="c:\\temp\0"; & \! R* ^5 U& p5 P0 E' r. S( R% T( |
//设置目的路径 & _' t3 V% C* s& |4 F$ A
, E1 m4 [4 W% X' C; K
char strTitle[]="File copying";
/ D1 g" ?& G* k2 K# }! [3 p0 n5 M //进度题头
, ?9 O( j; o5 ]# B ! G5 v+ ], y# s! v, B8 W
SHFILEOPSTRUCT FileOp;
1 K2 [/ P* ^, K1 q S5 U3 P; G
; R: p! e8 l4 x' S1 Q FileOp.hwnd=m_hWnd; / W8 C: c7 k4 r: d
! J3 W" Z6 ~9 ?; U/ c- k! L1 o
FileOp.wFunc=FO_COPY;
}1 l- b% E5 k$ b& ^6 R m; F7 X% Q
" ~( Y5 p+ Y) S# K8 e //执行文件拷贝
. E% Y& P( w- T+ \* S. z z( V% M( f6 q9 L
FileOp.pFrom=strSrc;
" x2 Z9 a7 V% V1 M0 _ % ?. ~; U0 i& `
FileOp.pTo=strDst; ) c U6 l/ m3 G' ]( Q0 ]1 E8 O v+ X
0 H3 R$ O5 t2 u% `
FileOp.fFlags=FOF_ALLOWUNDO; + Z( u1 V" p! K2 Q o
" l7 V$ S6 N# l I
FileOp.hNameMappings=NULL; , [- N: ~3 g' O+ x- T, {9 A
1 Y3 G! q; A) T! k3 M
FileOp.lpszProgressTitle=strTitle;
K, E2 r7 [0 g
0 a$ y9 o! |) }9 F7 M nOk=SHFileOperation(&FileOp);
) y, R# J. j% `% V& g
4 o3 s8 H1 x, j. x( e if(nOk)
3 t7 \+ G- ^- q& Y2 I: V4 C" O 2 e" M/ |9 ]6 H, x$ [, v% P1 n
TRACE("There is an error: %d\n",nOk);
' G7 F C4 D; B & A( G! Z' t8 Q& x9 L
else
' y$ o. Y1 y3 ~9 [( k9 h( F+ k
8 F& F" w! d$ [1 H5 e5 l TRACE("SHFileOperation finished 0 t1 o* N$ u# n( o" m
successfully\n");
: C% H4 i; B* w 6 m" V& F3 J V) @; E
if(FileOp.fAnyOperationsAborted) 2 b$ v' ?% g8 Y6 C- d% w5 F
d7 n7 \. P- e( w, i6 z TRACE("Operation was aborted!\n"); " c; N; ^5 x. s
} d+ L: Z5 R, {( ]' Q
& u5 M* S7 X# P# _ , ]0 b. C$ ?) Z0 ~2 ~# {$ f1 n8 V
三、 结束语
6 ~. a7 e) y. e C# } 4 a2 F( ]3 u. ~/ w
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 ! p; d2 D% P2 U3 x x% d
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
1 g$ i5 L, o( D8 z0 c1 b" }& X7 t系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调
: a5 u0 p, w! ?( t4 f @; c. k0 J用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
1 L8 e3 E" d; [. {% D
$ e- O- J& ]5 C1 N# h; H5 E---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
! [: D6 H; y* ~" u3 b4 X& k6 U到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
- Z5 C; f6 k, q5 d% G+ c8 @地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |