|
$ M& A+ H6 i; x7 ^# P湖北工学院图书馆计算机室 6 w. a! L2 F: |
张明武
( ^8 L9 ]+ d1 t1 v$ d* m+ T' q
. O+ s l4 J. d: l& L2 F2 K( A---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
: X2 ]% M1 L6 b4 e. G6 q6 ]; T操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
j+ C& f, W& f5 i/ m6 L8 ?4 O、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
- a" }! K; O7 o( C; i/ T. A+ D区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
! \- {4 d8 k# @4 t }! T库进行备份,很难达到最佳效果。 7 Y% h. Z- |0 H- q
+ E: I5 Y$ G. q, I: E' O0 G1 u
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 ; y3 Z( P# ~- U4 L" d# g
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 6 L/ @8 F+ X! o. H$ P/ [! m
可以直接对一个目录或目录树进行操作。 ) [* }0 D; k% m5 L7 W
R' Y* y1 D8 S. N5 V/ J; A
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 9 E' w+ {, i5 {2 E3 E
文件的拷贝操作。 . \6 x6 p! a6 \" t; x+ y' k+ N' k
0 A* l9 c, y% G) B! R/ z一、 原理与结构
0 H- n% u" c6 [! `. [! \
/ o& L" M- n) k# g: J! `* U---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 . u* w7 F6 r) j, v. j" d! [& k
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下: 5 K; i# C# k' t* g
/ A+ q! T" E. t' |: F---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
. `$ K+ W8 A; D' _% nlpFIleOp); 2 ^! t. D) A! G+ e4 d
( L; ]; n3 r1 F
---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
1 M6 U6 M! \3 S6 [4 _下: ) h1 H0 k. O; Y' g( X9 O y
, K$ S3 M( K5 d4 Y9 Y% d
Typedef struct _ShFILEOPSTRUCT { 4 x q M* m4 @, A! ^" f! N
; @! W& g; Q9 K- t- h
HWND hWnd; //消息窗口
6 ?( t& ?4 B% ?) s# {- B( `
( ~6 U6 c$ C4 ~# C UINT wFunc; //操作类型
* ^/ |( z& `* K# L' M* O ' W) N' X9 Y& h9 E: @; o4 g
LPCSTR pFrom; //源文件及路径 , V1 T1 D4 w$ `+ I! }% S: I
( {( L o+ p0 k LPCSTR pTo; //目标文件及路径
& H- t7 Q1 u3 W( u9 ?# R0 o
/ B' D+ g9 z/ _3 i2 v2 o* {+ n! { FILEOP_FLAGS fFlags; //操作与确认标志
! X! }3 t% ], k. { 0 ^6 K6 {& ]8 C: K1 m+ h# [: R
BOOL fAnyOperationsAborted; //操作选择位
' q w9 Y7 `( d2 q B: X0 K) Z/ w; M
LPVOID hNameMappings; //文件映射 ) b5 @6 K7 n u+ Z4 L! f4 N0 D# }" i
% W8 B9 g' o7 J( N2 ~ LPCSTR lpszProgressTitle; //进度窗口标题 8 B8 Z" r0 L/ o+ k" a
# \. l* k; j d- C# M
4 J* h8 w7 f7 u @" s- N& ~+ U, a3 d } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; 9 C' d1 U) b' i7 I
. q; v# y+ S5 i2 M( p% v & I2 r1 v; y% M( a" o3 U
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 5 p' k- ], k" `3 z+ T% Q
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 ( C/ w* d- x! @' X8 E8 e
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
+ t0 X: c* I# m. P9 }) p个,则应是: 3 _3 i( I' ^. W% f4 ]. Z6 J) [( s' D+ m
1 p' p k0 |7 o% B; ?
char pFrom[]="c:\\windows\\command , |" h' ?" m' ]% T
7 M8 {. |- G+ O4 |! u
\0c:\\dos\\himem.sys\0"
9 P) \: B$ q3 K0 F2 i. ]" X" H 8 S. y) L( r! P P/ o& F4 ]) j. C0 i
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
) d/ m% ~9 E" U$ N) Q进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 6 a2 b G5 D" u: ]6 U$ |$ g5 Y
要成员,它指出将要进行的操作类型,是下面的操作类型之一:
p- {% l- @1 ~, ?( t
- u# ]+ |& F* x5 b8 g, `7 f5 b ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 . p0 y, B8 Q/ B4 o
4 Y" I* c ]' Q( i0 k e8 w5 I
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 4 m% L% N- B7 N" A
$ y- E: v3 j! U; v
" Z6 a1 g4 r+ x$ V* M) k8 R& D ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 ! z2 N1 @" ~. c* B+ o
5 ~2 N$ V6 r7 d
---- FO_DELETE: 删除pFrom指定的文件。
: \( k7 F& V- U( y g z# q9 I. {# j: H" }% x' o
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
2 I$ T3 Z/ _+ ]; l- L程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 v* D1 x9 B0 |4 Z5 ]
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
# a+ e0 K& r( G0 H, v在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 - ?$ u+ P- b' y9 k& r4 {
组合。
# ?. l! Y( y* D5 l. F
& }: Q$ R+ W. s( s6 A9 _/ g% { ---- FOF_FILESONLY:不执行通配符,只执行文件.
* x* l. T4 q" n; U2 w; [
) I/ R7 w4 M+ U: d( }5 n+ r ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. ' z- [7 U- k/ v) q# }6 N
3 k: Z0 o$ w7 a
---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
' O% [1 t X5 O- Z6 {候,如
) a2 t6 N- s, S 果不设置此项,则它会出现确认是否覆盖的对话框,设置
' ^( H" q, {9 o0 \6 M( E此项则 3 w6 j) N7 c; T) ]+ |/ |
自动确认,进行覆盖,不出现对话框。 8 ?- y, D1 G5 `, v( _
. _! E' _8 K( Y; ? ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出 $ I6 {0 ?- M& a2 f
现错误
9 u$ c7 A7 @; H7 _* E 时,不出现错误提示,否则会进行错误提示。
! `; }+ E4 X3 `4 _. o. R% Y! c& W# N
6 G* m# U0 j! O4 l ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 * Q4 F6 O$ J+ {$ a" { p6 o# v( g
进行更
5 d( e( x! }7 o5 j+ r0 \* ~2 F 换文件名提示。
' B# ^, o n8 d" ~
8 ?0 c$ T8 R8 X5 J/ G# {7 L6 G ---- FOF_SILENT: 不显示进度对话框。 I& h9 @8 t- E5 t
3 v2 d% t6 V8 W* s ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() $ g+ v" a" s y R
函数返 3 f1 ]/ R7 E1 g. p# p; A
回正处于操作状态的实际文件列表,文件列表名柄保存在
8 e0 ?% I. g$ \
) J- R9 Y7 F( l( I2 \+ `* d hNameMappings成员中。SHFILEOPSTRUCT将包含一个 & t8 H+ m7 O L m
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
2 d2 S3 w5 [, d; H( A8 N" a0 g4 k个处于
% }2 }6 ]6 i& {# `* g 操作状态的文件的新旧路径。
0 S F1 z9 F, b+ ~ 9 X; Y" ]$ t! b3 y0 P$ O: f
二、 实例操作 - W. [/ F+ ~1 L& W
" ~' b. [8 ^: o% \ H1 w4 c$ [
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档
* N9 J7 ?# Q2 z# A6 E* H界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
; j* V; y* b% v9 W! r& E工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. ) y: h) }% \( T# |& d
cpp的OnCreate()成员函数中加入工具栏。 : a4 ^+ F( o! Z& n0 i b7 b
X9 X3 Z5 v1 L+ n
if(!m_wndMyToolBar.Create(this)||
! t, t3 r4 J1 k2 q& ^ / A9 [% p5 ~; X
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
: Q! o* ~/ K8 N- S8 ] ; P# a, Z/ T# c# x2 f
{ / m+ D1 D2 u6 F3 P! K( U
) q6 M/ E' O3 P9 f5 j- q; L! v
TRACE("can not create the FileToolBar!\n"); $ j4 S( L7 |) \% ]+ T+ B
. c# s9 O9 a! R& t. a
( T+ N# ?1 x! \' K. e return -1; ! x) Q5 Q- ?1 Y. T
: S, s0 {& X! W& W2 P
}
$ s" }4 y: ^& R- _/ J7 w. y
6 F" h6 E u' k) J% F# d5 I ( K" m3 \! S+ @2 x- h
---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
- U: \* G: P$ F, UID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 E$ A6 |: h; g% f. Q
$ p" {! o( l W. B/ V, T8 H void OnFilecopy()
- U: ?$ K: P+ F/ s! T { 1 _9 X0 C& R5 e& g
int nOk; 3 A4 L6 e3 u0 e. w
char strSrc[]="c:\\dos\0c:
) n# e- L5 l8 b$ X\\pwin98\\command\0";
' j, `3 k9 k) T3 H* {6 V4 |# y //可以改变源路径
) c2 O: {4 A6 P' U: W3 F $ N b) k% f/ V$ U3 v3 a
char strDst[]="c:\\temp\0";
; G7 G+ c7 X4 g" _: k //设置目的路径
8 U! I" i& f; r4 T
" _# S: y1 E0 H, n+ V2 v char strTitle[]="File copying"; 4 k1 S' Z* k3 a, j' s, x
//进度题头 * S' A9 Y, H2 `/ G
+ ~! Q3 w+ V2 H- \4 I% ?4 N SHFILEOPSTRUCT FileOp;
; K6 c/ d1 ?3 n3 G5 G
/ ^. e1 F: i5 }' {- r' i FileOp.hwnd=m_hWnd;
7 H7 Y2 g0 [& s* t0 L7 `" J 7 `! D$ D3 K$ e3 W, h" d0 }, C
FileOp.wFunc=FO_COPY; , _4 a! H9 I) k& E' E
7 W3 ?, x `, o, d' \2 q4 o% X //执行文件拷贝
. Y. ~. r+ w- G
5 t1 t# c, \3 N$ g3 S. ? FileOp.pFrom=strSrc;
. Y6 h% a) c7 J& E* D ! S, G( \; C# Y0 }* ^7 m2 B& I. ~
FileOp.pTo=strDst; V" E* _3 {" ]/ @8 e' C* W
7 n- N0 j* y4 y6 O7 q8 L' [
FileOp.fFlags=FOF_ALLOWUNDO;
8 z' O: h. ]' _
9 L0 z3 X: f! z0 T FileOp.hNameMappings=NULL;
( ^ o+ Z- x0 u: M4 R* w m: A, \( a u/ E8 N
FileOp.lpszProgressTitle=strTitle;
& l, L0 a; z! g, C2 \1 S& V$ x C6 h& I0 P9 s$ S( I2 b* e
nOk=SHFileOperation(&FileOp);
2 y$ H8 i& C: k. [5 n1 r : N$ Y+ x A- q6 p/ Z
if(nOk) " s: _: Q; A: a% ]4 e
4 \! b8 }, M9 e6 C* I TRACE("There is an error: %d\n",nOk); ' t% d2 s( |9 @& A; C
1 ^* H2 D5 h! W& h
else % m4 P. K. Q6 `1 E
" i% y f8 s' p" x; y9 x
TRACE("SHFileOperation finished
7 X: M: |1 C# L, O1 N7 Asuccessfully\n");
% h, s& x1 B# \/ H 5 i% w0 L5 m A
if(FileOp.fAnyOperationsAborted) . ]* j: x! k, J0 d: O; a" g
% M9 ~5 Z/ \5 U3 Z
TRACE("Operation was aborted!\n");
! Q% f& A' e y$ _) {1 v } * s; W c' n1 N5 E1 I3 A9 [) E
- d; ~+ ^/ J: l: c9 O$ q
$ Z. k" P# T9 n. o三、 结束语
' E2 Q/ [2 e3 Z. I5 M 6 |' o" @' f- Y- D
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
% X2 M( R4 ]) h) q( ?的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 6 m, e$ Y7 _8 I9 |9 k/ T" E
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 ( G: {( e( {! R+ q
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
4 @ e- s: I- ^+ p
. O( N/ e' ^) v2 x1 j }---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
/ L; q$ E- f+ u' W+ f到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 ' F+ z4 v- O9 Q# I
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |