|
5 N7 t4 U8 o. F4 y/ f
湖北工学院图书馆计算机室 2 Z( h, ?9 m' q9 F; X: K2 v! V) s
张明武 3 P" t' f; j+ r/ E7 C. Q
( X: s' N$ A( ?& j---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
/ g1 m3 {. `" C$ r操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
5 \+ B/ y3 H% Q; E' P、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲 8 r5 P5 S* {- h5 g# V
区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 1 ^" d3 K1 D5 d% O' w# r, O. _
库进行备份,很难达到最佳效果。 . v2 T. _3 a) V1 Q
7 ?( |9 g: y- W# y8 _# ]
---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
( b& Y% e2 Z. {0 V现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 7 x: b4 k; N5 P. K/ N2 M' @
可以直接对一个目录或目录树进行操作。
w% R* h ^! [ n4 y# F 1 O+ m5 D$ `5 r7 T. L9 P
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
& a/ s9 }# v; S% B" z: B( g文件的拷贝操作。 0 J8 v; l: V u& }- K
, e2 c/ f4 k6 B* e8 L# V! c% N+ o
一、 原理与结构
% k' t4 A6 c9 I
+ [" t' | t. X' W4 C, X, ~# J [---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 $ \0 ]+ Q- D6 z; H- Z
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
& }; f3 `, u9 I- ? 6 n5 i2 X) d H) Y! ^) ?3 x/ p& L* e
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT
# j6 E9 ?2 ~( i& w% X* B" M; NlpFIleOp);
' }, C6 r7 p" J) X7 H7 D
0 \3 n/ X# Z0 J6 T& c7 E" [: E ]---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
' Y4 c: Z9 I& z下: . U6 U, \# m0 F4 ~& `
- ]! q6 }% }) k" ?1 t Typedef struct _ShFILEOPSTRUCT {
% F! w2 F8 a0 Z* b# S1 Q - n- e' c+ {$ z: U' J# y& e
HWND hWnd; //消息窗口 ' a0 Y; i' c9 B. L
2 _& R0 x/ G) W* Z* R# A
UINT wFunc; //操作类型
+ C' Y: k3 `' l; T5 D( e; j ; H6 o+ q' A) W6 J0 s# y
LPCSTR pFrom; //源文件及路径 ' T% Y% q6 a' h e+ M. ~
4 Y. u# q: P; y% S
LPCSTR pTo; //目标文件及路径 0 T! Y, U1 P( E) w3 ]6 r: k4 X% M
/ d9 ~! i( @% {' v9 T! y6 P FILEOP_FLAGS fFlags; //操作与确认标志
) @4 N; J& x0 @9 N3 [
- \, d5 @9 T# @+ u" U BOOL fAnyOperationsAborted; //操作选择位
$ P) W$ f) A5 ~, v - V; T0 c. G9 t3 a4 w
LPVOID hNameMappings; //文件映射 6 N y' d, P* [0 ?
' t: U: n0 ^2 O* Z! J
LPCSTR lpszProgressTitle; //进度窗口标题
3 J1 w: m4 ^) R
% D/ m& J. }/ e- e8 g, P# Z
, l4 p Y$ e' A } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; 1 P- \3 V6 |( h5 E1 e. g. h+ v8 Y
/ S+ I: I- x5 S! i
, J! R* S3 `+ u8 k
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom 9 g3 n* {0 m& f: i o
与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
& U* \ B* ~: q文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 & Y6 v- f0 B& d3 v1 F r
个,则应是:
: o' X* p# o8 w
' ` j1 F+ R( K; c3 {, l+ K char pFrom[]="c:\\windows\\command
7 x) @/ L T$ N7 b
, [! t3 |# n+ I' u% v) Q \0c:\\dos\\himem.sys\0" + h; ~1 X( i9 R) Z+ s
1 I; ^5 l. @1 ~; m% ~- @, y---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 / A c" m1 V' [2 }9 o' o
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重 ! ~2 r% s/ G1 t K
要成员,它指出将要进行的操作类型,是下面的操作类型之一: : [4 U! n+ ~; Z# `' ~
- R: y" F4 ?. A9 ^; q
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 , X6 q: Q! I, T4 h5 |# {
" Y) k1 u- B0 f: h/ p8 |; Z0 a/ F4 M
---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
+ p. d( `# d; Z$ p8 u
# M9 } E! R2 e) I% n' _ , z7 f+ j5 t( I, u. Z
---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
" {" R1 R9 l9 c 4 W- ]% W3 Z. R' K' [4 ?" _2 u. t# o
---- FO_DELETE: 删除pFrom指定的文件。
( \: l2 J( G9 {# k5 w# a/ o$ L
& a1 H3 u- O0 {0 o# I: i6 w' d6 s---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
# j8 }" d1 m! Q) c D) H: P程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
2 b& j1 ]" M, e) U& a* X4 d7 t3 I移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 r9 l3 R2 e- z1 [1 A# R6 i- u
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
2 K% O9 Q N, c组合。 ( Z4 Y/ w- E. }8 L1 C3 S5 P, Y0 n
: l5 Q) b( [5 i# J( z4 i. i
---- FOF_FILESONLY:不执行通配符,只执行文件. ! p% N0 }$ Z; q O% ?* |' |5 M8 C
2 K' ^# X0 F8 y) E ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
) y* z6 ?& h) K% _+ u$ R
6 W7 Y5 m$ L) _ ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
# C# k* Q9 K. u候,如
" B5 |, l: o+ Z9 u, Y 果不设置此项,则它会出现确认是否覆盖的对话框,设置
" j( @& w% l8 E! I: g/ w" M此项则 4 H' G$ W i/ p2 _7 y" V: T, y
自动确认,进行覆盖,不出现对话框。 : X) B8 `# I7 u
" W' t$ W0 f4 T- }0 P& o! v ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
- i( ]9 w' ~9 s" F# O! |现错误 * F; b6 s" H8 P4 T7 v
时,不出现错误提示,否则会进行错误提示。
8 Z( F/ H1 o" D" P
+ K+ s- B2 e0 c ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
7 a5 M; [+ k O$ `进行更
3 g+ p4 J2 z1 [9 R: ^# K 换文件名提示。
3 C' ^ I1 R* a& Q+ J' ~
7 V# ]- [3 ~3 N ---- FOF_SILENT: 不显示进度对话框。
$ r+ H+ P" s" p
7 m) ]8 S1 K7 j, |5 r" D6 H9 t ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() 6 D1 C4 m- h7 I- I" c
函数返
) o1 H% c. W" j! ?! _9 j 回正处于操作状态的实际文件列表,文件列表名柄保存在 , }8 T' I' W: A* b9 ]" m
9 O: B9 p, a+ \% l1 V5 J8 k* h7 Q
hNameMappings成员中。SHFILEOPSTRUCT将包含一个 6 t/ s9 z: y% _: K
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
! X4 s7 _/ {) E. O( M个处于 9 ~% N4 F+ V! ]4 m, X8 h; {7 L
操作状态的文件的新旧路径。 7 Z; B0 |# I* f/ }, ^3 \
& O( b0 D5 I7 ]7 [5 c* e二、 实例操作 1 |, z; {3 O p8 W' i
5 r- E+ O$ s* Q8 f1 P; z3 f5 Z# G
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 - V' X: e) _. I o
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个 " ~# q. A- ?4 w, s! \
工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. * P# j+ T6 O4 v
cpp的OnCreate()成员函数中加入工具栏。 $ Q' f4 D) M9 ~& q5 ]- q
1 x9 ~" {7 ]6 I4 [
if(!m_wndMyToolBar.Create(this)|| 3 |% }! h1 q& I) ?$ H$ `
/ {7 a4 S% J7 J4 z !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
- j5 z. }/ X) \. X5 v 4 x9 H! l* r9 V7 W
{ " T" h: [3 L# O9 Z$ z, E! D5 Q
! H) [3 U, G$ J+ S$ J: b8 J TRACE("can not create the FileToolBar!\n");
\. i8 ]' _, Z0 z) P" _+ V+ \ - c+ l# b. r0 T* ?
# c+ z# {; H1 V1 a: E
return -1; : t8 l. q: X$ ~# {+ t! }
! j4 {+ f* Y4 N( D! [ }
7 H% ?- ]+ O/ X
5 B S; H v) P0 A R; F$ v; u, V
- i8 e; k4 c' L4 W---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
6 p% a: T- Q/ G! k+ q# Y& [ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 * P- t3 e( G) c# C. |# C! s* f9 |
! O$ g+ l3 s* v$ X& I; N$ l void OnFilecopy()
# @$ A$ W/ e* `; E5 j { - b( ?2 k; B, ~$ O& {
int nOk; : v5 ]' j6 U; g1 V4 |/ g
char strSrc[]="c:\\dos\0c:
# o8 M6 c" L4 r* D# A\\pwin98\\command\0"; % N. M1 t9 [5 |0 [! l
//可以改变源路径
5 s5 q5 @' t% T1 V
; H1 j3 R3 X0 x char strDst[]="c:\\temp\0";
3 v* m$ T. h9 L) d9 G# I //设置目的路径 - X* y3 w9 Q4 Q
- k0 P: {( Y# D2 a. ^: r+ d9 q
char strTitle[]="File copying";
$ @( q. e+ E* C; @, f0 ~0 @) | //进度题头 / P6 C2 ?/ V2 z4 x
4 N* {$ n' _3 r2 T- h SHFILEOPSTRUCT FileOp; 0 b! s4 Z3 p K; Z; g' E
8 e I+ _6 _, s z' `7 z
FileOp.hwnd=m_hWnd; ; q V4 w: @# {; o3 `" J5 S# r$ ~/ t
; Y( L7 a9 u4 A% _. R' U
FileOp.wFunc=FO_COPY; 4 H7 ]- ?) ?2 L# \- q4 m- A
' p) T1 ?. X$ G8 V2 a4 P
//执行文件拷贝
5 ?2 C# D) I8 a1 C
# M9 f3 H$ v! p8 P' [9 X# h) E, n FileOp.pFrom=strSrc; , c9 `, `* E) h1 \. i" q0 S, x( L
r# e; l, M1 ~5 J/ Y6 \; T FileOp.pTo=strDst;
9 L Q0 T3 f" Y4 _ k) G. P # _9 x: K# V3 I$ V
FileOp.fFlags=FOF_ALLOWUNDO; $ `* i; f2 g. T; X
$ S& p6 R% _5 V- d- |9 O6 p
FileOp.hNameMappings=NULL; ! Q8 F3 Y' U+ X7 [& G- w
0 P; _% q4 x; Y* |! t$ {/ j FileOp.lpszProgressTitle=strTitle;
6 Q' B/ ^( D" x( x3 m
. Z2 i- a! D- D% I: d- m, f0 L nOk=SHFileOperation(&FileOp); : B: D r3 g1 Q+ t$ x: L3 Q3 y
- ^$ U- J4 {* H) X( |" s6 C
if(nOk)
v% r. d( m. s & ^/ {3 o: \: ]0 S6 k" K5 i0 V
TRACE("There is an error: %d\n",nOk);
! ?) _4 |$ f- a+ L Z5 @& Q; G
5 Z u* g# Y/ X8 i5 F$ }( B4 X- R else
4 U0 z- f8 l! \+ u+ N
# u" }: x4 y9 I+ ? TRACE("SHFileOperation finished & P6 T7 @, @& x+ g: s+ z2 s
successfully\n");
$ q) S) i8 W4 o: o # R: k2 L s/ r1 Z. ~. g& J+ _
if(FileOp.fAnyOperationsAborted) 1 x5 \+ a; c+ A: Y5 T. q; `
0 p6 Z9 y+ ?, o( i
TRACE("Operation was aborted!\n");
: P: x$ q; ^, j; ]# F! B9 e }
. l7 i& c) h0 x$ z. h& d
, p Q: w. A4 }$ m+ P7 O2 v
+ c+ A% U* O7 X6 @三、 结束语 % B2 R! V5 t0 W/ ~4 \ b
; o8 I/ F! u. ?2 w0 Z/ H
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 " e& E- O6 k/ L$ q% D! [/ r( K2 V6 j
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 ' p% y7 K9 n( Y2 o8 S+ a& ^
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调
6 W/ h8 B" a! M6 O6 Q6 j用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 7 C S! y) f; N0 ]
) ~* q, c Q' d* \5 @( n1 Y
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 2 `% T7 }( c4 t6 g3 h- `
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
$ I; }+ n- c0 E* X' I9 P' s+ R地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |