|
' V% z) Z. ^0 W! C9 g3 Z7 f湖北工学院图书馆计算机室
$ J' ?& G2 i, z% G9 E张明武
) C0 R# g% R' }9 s
. F3 u7 m" X% w; t! [+ A" g0 C% ?---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
5 k0 G3 r7 Z% v操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE e- G9 f. }8 e& \* \9 {
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
6 B% |( }5 M4 ^& s$ b8 `区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
5 O, o n2 Y: U/ B! r) I) M库进行备份,很难达到最佳效果。 * W, D0 V1 t8 U* U' Y! t/ [+ l
7 ~6 ]8 K0 C5 i---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
- G" [9 O9 A6 g$ |( p* ^; R2 I( G现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
! M! ?4 l& x( |* X. p) r2 L可以直接对一个目录或目录树进行操作。
9 A! v& Y1 t1 V9 M& m ) r# N: U. N/ p6 u0 |
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
: w6 }/ x. ` L, j- t文件的拷贝操作。
$ a1 L' Z |6 ~- |) G- ` ; a- S! \/ V) j* G6 }; e/ h
一、 原理与结构 6 l( z2 Q, s" u* H
Y3 T2 a& K- Y9 S1 Z. Q
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 * C6 k- S2 y5 g+ s0 I7 H
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
0 i1 H9 ]" ?# @/ t2 `4 o7 ^ - C: L: K' K" R7 P
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
7 l# P4 F# A2 GlpFIleOp);
& R/ [* A8 w, x$ _* {
# @9 j a+ a2 r2 D---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 9 G: h4 j8 X v. o
下:
; V X) Y& G& Y* P) t
# s! h3 s* N# [- z* \; p f Typedef struct _ShFILEOPSTRUCT { 8 {# ^! F/ Y( E0 v0 o1 P( P
p! I! Y8 l+ ^6 t
HWND hWnd; //消息窗口
% A: Z$ o5 h' k 4 S! t; z6 O0 b! m2 e
UINT wFunc; //操作类型
8 `3 n" [# z, x2 W ) h t& n! ^" E& Z. \6 F
LPCSTR pFrom; //源文件及路径 & ^7 P7 V2 H5 |, J
" ^2 Q' W! W2 K5 t) m* s( b
LPCSTR pTo; //目标文件及路径
% B2 n0 }1 J6 Y/ k/ \2 V1 |) c
) o% ^; _5 A- h6 T0 w; ] P& ]; F/ Y FILEOP_FLAGS fFlags; //操作与确认标志
5 } I& | D" |6 h 0 S* {2 L3 Q7 o% V, a% j$ [. E
BOOL fAnyOperationsAborted; //操作选择位
3 r2 I, I* p/ \+ e" g* Z, f
& w+ h3 O( d* @3 [, |( k' X) |4 ^ LPVOID hNameMappings; //文件映射 - v0 _3 R/ I4 X% L6 T
$ P4 S3 ~1 g% G
LPCSTR lpszProgressTitle; //进度窗口标题
8 W; O/ ~4 d$ [- O
$ l( m' w+ b5 y$ ?1 z/ h4 u : D/ W$ E( d. J& |/ v' o% }0 ?6 A, r
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; 9 T& \% K9 |- E- z" R0 K7 t _
$ {8 o; `1 e. U: E0 n* y2 n
* Q7 R$ Y( h- k# h+ `1 w4 k ---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 6 R* N; L @; @# J
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 ' R, Q c7 q1 }! R+ s+ C
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 + Z* f$ R* e/ _9 q2 h. F0 x7 [
个,则应是:
! n f* V5 U5 f* B5 E A ( e2 g( c7 f) }$ D( o7 {1 P
char pFrom[]="c:\\windows\\command ?) [& S% T \& x& Z& J$ c% W# P
" N. v6 Q# j j
\0c:\\dos\\himem.sys\0" / P, @8 Q, `, _$ T5 n
, D3 q" Q) l7 t2 h1 J5 U3 e
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
+ z3 G/ K+ E( t1 Z0 {" r进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 . G( ]4 [. v1 c) B) s% J( v1 i
要成员,它指出将要进行的操作类型,是下面的操作类型之一:
/ r% R9 J( |0 T, \9 r
3 g0 _$ o) A* m0 [ ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 * T6 ~& h) P: `
: Q. B* ~* G% Q3 n
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 8 ~2 b* P5 \+ A: P0 o. R, o
- T" H: y9 p3 [( T
' \" S( X: \7 G, K+ c+ J, ] ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
7 }6 Z9 j: l5 B2 d
6 c- }5 j; b- Z9 V3 S7 E ---- FO_DELETE: 删除pFrom指定的文件。 . {0 ?& S' j, y
2 A4 J7 \! S7 m9 r
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
0 E# q8 |/ }8 k2 o程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 % w- ]" b/ E3 }) @6 ]8 \9 l' K
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
, I: S' U0 h2 b" G- S在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 # [! [; L) o" C- v' C
组合。 1 b1 H$ S2 N( b
6 [7 D- `, e' M( _1 f, Y/ o4 ^ ---- FOF_FILESONLY:不执行通配符,只执行文件. 5 _3 I- V1 h U% p: t% ]
d& x/ l2 N6 ]7 e- r ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
0 j/ d. c2 u% L6 _5 M; Z2 E
2 N4 h2 E# F. o _ ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 3 z$ E. O3 s2 f- b1 @
候,如
$ L& _& h/ [+ l 果不设置此项,则它会出现确认是否覆盖的对话框,设置
# N7 U3 s+ b8 W4 k% ~1 j/ T此项则 4 C: W8 ]+ n( [6 Z6 e3 Z
自动确认,进行覆盖,不出现对话框。
: {8 j1 y( M/ G2 a9 t; e- g
; W7 u9 f$ m2 m f9 m ~* I9 ? ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
' ^, F( A# T( N# H# O现错误
3 M% J7 p% e, ^& E( |0 ^ 时,不出现错误提示,否则会进行错误提示。
) @9 g* X5 v0 ~: `, V- z3 W/ l ; L$ R# g/ \# }6 g
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 2 f2 j _4 J9 i# _+ {4 _7 b! G
进行更
9 _2 F4 }5 l: {: }; `2 v 换文件名提示。 & ?3 ?5 i( C! C1 e
7 W8 P0 O3 x% M; R( s# r ---- FOF_SILENT: 不显示进度对话框。 ! y* P5 l( [2 S
" C9 V6 ^* [$ }6 s: y; s! O4 `
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() 9 r- H! r$ \1 o* k( u3 ]0 a( ^
函数返
! ^7 T1 K: e$ z5 K' [ 回正处于操作状态的实际文件列表,文件列表名柄保存在
1 k7 ~0 L9 Q1 ^5 q* s" _
2 X, o2 H4 K4 v2 F3 E, m hNameMappings成员中。SHFILEOPSTRUCT将包含一个
; g, X( f- e$ T2 w3 E3 M' [( C+ f SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
7 u0 M; {& @, h/ O; t个处于 t8 S e. e/ f+ \% s- v
操作状态的文件的新旧路径。
! y9 e; {8 Z- W7 X1 I5 A, |3 @' X
+ h" C" E. L9 ]* n/ x二、 实例操作 ; y% v# g$ v! ^
% m* L: E2 T ~; o/ B9 f---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 x/ w* |" R- y5 F
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个 " l. r# G" _9 A
工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. . z M9 e0 ]1 ~% B: Q( P
cpp的OnCreate()成员函数中加入工具栏。
0 W# C1 ^, K& i # G4 d' {1 V& K
if(!m_wndMyToolBar.Create(this)|| 9 j8 o P1 f' Z" k
: {& G5 p) ]1 O' Z3 K !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) ( l, s/ E! S6 m! h+ \! K$ c8 @; V. F
5 I6 M9 Q/ P) q8 o& I( ] { 1 H. b' w5 B; a, ]/ u6 L/ i
) i* @8 ]! e) X: `/ q( T9 r
TRACE("can not create the FileToolBar!\n");
$ g& s9 l( S, O! n; f" H* m) r3 [ 8 G* a. l \* q7 Q
% \" S; h& Q+ F: z7 w return -1;
- k, R/ s1 M+ M# b8 e
" z& s2 M7 }6 U4 U" ~* g% E: } }
! e$ h0 V6 w |3 r. }/ q
, _: @4 `9 h3 u* e, v) P . \3 A0 m7 z) y- o
---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
3 E0 U7 a: O( N* s( ^' cID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 ; z1 @! T. x2 ~1 {# I
4 r- K1 v6 T/ P9 X
void OnFilecopy() * W' E" \ d, v \
{ ; d9 \7 Q8 |9 T. [; l5 F
int nOk; & c7 L1 u& {! e/ m5 f. e
char strSrc[]="c:\\dos\0c: ; U. ~( V6 @: H4 E1 Y) ?) k% U
\\pwin98\\command\0"; ) [" f: X3 G) |; A s& {
//可以改变源路径 8 s7 S {" y6 i; @* }
$ q+ P: h' J5 N {, v& T2 q char strDst[]="c:\\temp\0"; 8 [$ u$ y5 h+ }
//设置目的路径 , W* c; y; x/ [) V2 S3 U% K
3 r6 B: s. D; Z4 I5 |1 x; B
char strTitle[]="File copying"; ( E7 |. d# R0 D8 e
//进度题头 4 f/ u0 X1 I* {5 w- m# f+ P
' x# V0 i1 c. V' Z- W
SHFILEOPSTRUCT FileOp; 1 v$ g4 C* Q! h+ Q& h/ Q3 w" Y
* W" J4 r5 ^' J! h3 x( l- N
FileOp.hwnd=m_hWnd; 7 r; @. x1 l' [4 D# ~2 Y3 j5 l
; e. I) W5 l* c6 O FileOp.wFunc=FO_COPY;
1 n9 Y* y' @ e8 U6 x# L 4 b3 i7 w; m1 X, _+ }
//执行文件拷贝
3 ~6 e( B! w) C k
. V& l4 X# p: Z; j FileOp.pFrom=strSrc; & ?, t5 V0 H8 k3 h
7 o8 t e9 t. M. l
FileOp.pTo=strDst;
( `$ c5 O3 R1 I0 {. J4 T }% `/ r+ b9 H7 G. y+ \" ]3 i
FileOp.fFlags=FOF_ALLOWUNDO;
* f, O0 l; M6 x# `3 s: Q7 l
7 v8 K7 A5 ?( B; E, v& d: U+ q FileOp.hNameMappings=NULL; ' c& e) H" E4 O8 H8 a
Y9 W3 }4 O; W1 @9 g5 z+ Y- U9 B" r
FileOp.lpszProgressTitle=strTitle; " q) G: G' V6 J' m* O- G
8 V: t1 D4 G/ Z8 p. e- J. w9 s nOk=SHFileOperation(&FileOp);
, [( M/ q: U# K
5 k8 Q3 h4 p. ^. i' S6 L9 z' {& z if(nOk) - K( F1 y: h9 o8 b* f |1 ?: t1 ^+ F- ^9 c
( n" o5 R8 M& W5 R9 v2 m
TRACE("There is an error: %d\n",nOk);
# B5 U: U/ P2 j7 a( [% F: ~ 3 `, A- F, M; F: V, z8 {
else 7 C* c: }1 |4 x" k% c! t X
$ t7 B6 R; H( i' ?
TRACE("SHFileOperation finished 5 n% c* v$ e0 l* D
successfully\n");
: s* J* x7 p1 ]0 `! V! J! G v
5 e% P4 p; h: b0 ` if(FileOp.fAnyOperationsAborted) - J( `0 z" q5 R- ]8 i* ?
6 Q- H* J1 O/ B X! C1 M& b
TRACE("Operation was aborted!\n"); ! H5 ~6 F: c) l; q
}
1 b7 m" O8 w9 u( E/ N9 p8 r& ~, @: J
. p U9 F% t ? E& G6 N5 n' h
. [1 f1 y# z k l3 @三、 结束语
$ j9 {+ l8 @5 J4 o* b% ~ , a. H- U5 o2 h# d
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
! z$ D5 L+ A1 {: `/ [的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
/ _% h* `/ X& b9 D/ l: R4 \系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 ; W% t n* b5 V& X. R
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 1 b9 j) x7 d5 G9 S& O+ Y, t/ d
5 [8 B8 }; m5 i% O+ b+ x% k& l# \! ^: N---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 6 j. y1 Q( @5 Z0 {4 M
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 2 m& b: p5 H- M M( s
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |