|
& e& f; o) D; @9 n* R湖北工学院图书馆计算机室 # N$ s% j2 s( V2 W
张明武
" Y8 O% G/ }' ?' Z9 D. ~) N
- j5 b/ P( L2 m! F2 [---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
! _" g4 d' o( k7 ?! ?1 e操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
, C) i6 @' N. T( U、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
5 k) F8 u: b7 k2 p" j+ ?) h+ u区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
; O+ B% g( h' C l' l库进行备份,很难达到最佳效果。
) B: T; V2 c% j% e/ h, F m" ?
2 ?! h* M; n/ }, Q---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
: _% ]) g4 m1 A6 m7 ^" K8 ~现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也
2 o" h6 o7 a6 n, h; U可以直接对一个目录或目录树进行操作。
0 K6 q5 n4 r& |: c2 Z
( ?! { i$ ?7 E! H5 M$ q% f! N- L---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 7 k" {. z; k1 R% T; m; t- y
文件的拷贝操作。
' p4 d1 T) Q S5 A
8 |$ t, a; k4 M# B一、 原理与结构
! ?( b$ k% }: r8 D, B" q+ g 9 b4 U$ S0 k, F5 a4 K
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 , v: |+ C, l o: o, k& _
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:
" m6 }" }* V* p- f, ^( v3 ]0 q 3 w3 H/ c2 W/ G7 y. m1 Y, w
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT 5 h2 @, i3 U8 x- e# p
lpFIleOp); % m) G$ v$ N$ P7 Y' E
4 y, _" e( P* Q: U0 U---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如
- O8 L- g! ]- v* b) X. u4 }2 e下:
3 i% M/ e# |, p7 p) K) S5 A 8 f. f" M& s- a- M
Typedef struct _ShFILEOPSTRUCT { ) V; \0 C+ U; L" T8 K5 T/ \; @2 A6 z
1 b: Z2 E1 Z8 ^8 u ]- N$ w3 u HWND hWnd; //消息窗口
/ S( p! g9 Y- R" |5 o& b1 H / P: E6 @5 K" T5 L" T, ?: p4 u5 R
UINT wFunc; //操作类型
! U! J; ^7 X" J: F
6 F1 g2 e5 c1 v( J* p LPCSTR pFrom; //源文件及路径 . r8 s. B3 H q
6 ?% r, [' s1 B+ Z. T' \
LPCSTR pTo; //目标文件及路径 : s" ?9 |! d* e, M
& V. P$ L" a: H# C; |+ C
FILEOP_FLAGS fFlags; //操作与确认标志 $ e9 Z/ n+ A; z5 A* a+ e
3 P8 r& g9 S7 R" ]8 A5 V; { BOOL fAnyOperationsAborted; //操作选择位 4 P( N/ T3 n2 a" G. P+ l
0 z& `8 d$ U8 B LPVOID hNameMappings; //文件映射
) Y3 R# K8 ~" u& @/ Y# p# H 4 k; [, Z v4 Q. i/ k% Q6 b( g
LPCSTR lpszProgressTitle; //进度窗口标题
& b. ^$ G$ h2 q: x3 B 3 e: w, M, U# J/ v. W
4 Y9 h7 B t6 X( D+ W } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
7 e+ x7 E3 u% L! ~8 f & X- P; ^8 z. k' {, y9 h4 _* R$ N' j
" S' `1 E% {% G4 H5 O
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
2 U, b3 p% G6 d. m8 s. K# v与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 : Y) J0 T6 D5 o5 Z) n. Z
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
1 ?; b$ _, R, \个,则应是: , G3 D; I: V. o& K. X1 U2 P
; }6 _) f. ?# M1 E6 `* F. A char pFrom[]="c:\\windows\\command
2 D7 K/ I8 }6 H0 H( \5 L! C & N: ~, u0 z4 H9 G {8 J
\0c:\\dos\\himem.sys\0" ; O2 t) v1 \" _5 W# f, n
W& m/ F, ?) v1 e
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件 " m2 B+ v# m; `5 l8 T4 Q- w6 x
进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
! ]7 c C V4 {1 j. h& C要成员,它指出将要进行的操作类型,是下面的操作类型之一: w# j4 o% b0 c' x t3 H
3 h. o* J3 J/ j7 b
---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。 ' w3 Q/ O- x8 \, a& \' _# V* |
2 l# S# G# S; `; n% ~* S ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 V. |- K% c6 \0 ~1 ~
: g6 h9 z' j# Z: k; R- N
# z6 {. K1 w0 c: m% v$ V
---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 * N" _1 g4 G, E9 ^* l0 n
' p2 I3 Z9 [ k6 {) F8 }7 s. H7 b
---- FO_DELETE: 删除pFrom指定的文件。
; u v- x. q; K0 s! E
. Y7 S6 h2 q8 P0 l J4 x: e---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过
; c+ e# b# p# i6 j& o4 w0 D程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 . B# h4 b% l# Y; A
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 0 F9 f" R$ P% B- m) U) ~
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其 5 S8 L) t, K c/ R/ f
组合。
- F, X2 t5 j/ P/ q5 b [* w3 _$ X6 n6 n
---- FOF_FILESONLY:不执行通配符,只执行文件. : f0 c- v$ q1 L0 K; Q! q) a. W5 Y
( z, a/ Y- v, q$ M2 }: a1 o& E ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.
* ] ^! ~* Z( y) I& f% H( u- k7 x
' C8 R- Q- O4 r. }' T, P ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时 . W; U3 c# `3 M O0 n% g; \
候,如
, k. r" k. R4 k% g' Z! z. N% @ 果不设置此项,则它会出现确认是否覆盖的对话框,设置
9 C) a! o2 I- p此项则 8 Q. g$ c5 K$ i) b( l0 H6 f0 x
自动确认,进行覆盖,不出现对话框。 8 u5 Y0 r; G) H- K3 A& v% L
) T5 Z' l/ h+ Y7 }/ g6 r R) r. n ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
( X3 v/ q* M" l7 h' N现错误
7 S& o$ d/ I& t0 h 时,不出现错误提示,否则会进行错误提示。
; @- P, [& C$ W- Y* g% b - N: X5 B5 Q. Y9 h3 x3 O& u
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
: |! }+ ?& E( t- _& u4 Z1 a进行更 6 h Q: Q: ]6 K! N( s" u t
换文件名提示。 % S4 y, C* X. K7 a6 ~" S
! `; N: M) _5 Q4 q" t6 O
---- FOF_SILENT: 不显示进度对话框。 t# i; `: [! f! h" J$ w
7 Z! p1 L& r, d* a& l# {% J
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() # X% ~3 _/ B* |
函数返 & S' o6 t- o5 c/ @6 `7 c3 A8 z
回正处于操作状态的实际文件列表,文件列表名柄保存在 & M6 k3 g5 d, e/ T) N
! H {( A3 O" D/ J
hNameMappings成员中。SHFILEOPSTRUCT将包含一个 + W) ?/ j# o! o: |
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
! N$ h2 ~6 h: j6 \( X个处于 ; S2 w, \( G* o
操作状态的文件的新旧路径。
0 y/ X7 h2 i4 d9 H8 `# J1 j
+ N7 q* l. ~' S U: J; Z二、 实例操作 8 T5 q! G* ~1 M' _2 n
9 X/ U# |, c5 M. f1 v
---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 : f5 v6 N: k* b
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
5 Y5 K0 `; h! W" w2 M工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
) [, p& o7 W& z' P3 Acpp的OnCreate()成员函数中加入工具栏。
( m( V# }3 R6 P: n4 F
3 b: C& F& s) s. L! s' P if(!m_wndMyToolBar.Create(this)||
6 Y' G( f8 K0 w! S. h2 Y4 t7 ^2 E
2 B* j6 ?! q T& E !m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) 6 C- s# E, I7 x) y- B
1 J- R0 f; w, }' _
{ 9 ?# z$ [) y* D, C
9 |3 }3 [3 m8 U2 Q: A- B
TRACE("can not create the FileToolBar!\n");
. t6 q6 P1 L; _" N" ]4 T. S4 y
# I1 ~$ [6 T: U4 U
0 U+ y& X: m x5 Z3 E" J return -1;
" G9 Z3 u, R: f4 g0 P8 t" l / P4 Y3 J- `0 Z2 `( H3 n, h" M
} ; H6 e# F7 z! ~4 r: N; ^+ o
# W0 |. G; T) ?& K0 g
" W0 u7 p. _9 \. R, ^# s. @. q4 x---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
/ F( Y; @3 S2 F( fID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 , x& f! l6 f( \( W( E2 L3 z
( J4 s! m: A5 I
void OnFilecopy() 9 R4 G# S7 b: N$ E! ^- B
{ : D" i" q4 w/ m7 M5 @) y2 ~
int nOk; . j( q3 O: {: k- M! ^
char strSrc[]="c:\\dos\0c:
# U/ ]) v( ?" R% z7 t\\pwin98\\command\0";
7 r/ S, O* c( {" k$ i //可以改变源路径
6 j" i" l- O* d# Y+ I' {% M( o6 a
/ t/ Y/ Z/ l. X; |6 _# g3 U char strDst[]="c:\\temp\0";
6 u- m$ b5 v0 W/ d+ {$ r5 f0 G //设置目的路径 % m1 `7 x! @4 \! u; G& Z& K
5 r- q/ ]0 h b
char strTitle[]="File copying"; % z3 Q0 H0 ~- _1 f
//进度题头
$ P8 K$ W% o: `- Q: k* L6 y
% d6 D8 o$ v' z+ x9 N/ G- F SHFILEOPSTRUCT FileOp;
- V, {( J1 c, E1 d& M. w/ Y4 n/ |% t
@. s' m% d* y3 S" g F$ |2 Y FileOp.hwnd=m_hWnd; 2 L2 l- T8 H7 G C+ h# n
# [4 c: c' H. H0 K5 ` FileOp.wFunc=FO_COPY; : h0 S: W6 E: G
8 n( h* p0 C- I //执行文件拷贝
9 O: }/ h+ ?! O X1 R @ & L' G9 P9 u/ F& ^
FileOp.pFrom=strSrc;
, [% o5 _( P- `# _
/ A4 Z+ b' R) ~9 i FileOp.pTo=strDst; : `6 B4 P! O6 E9 H) z
/ [ H4 |8 U, h. v% v+ X+ [/ y; ], T
FileOp.fFlags=FOF_ALLOWUNDO;
% Q5 i5 K: h1 @3 U ~5 N 6 }2 t2 r2 o* a0 o$ P
FileOp.hNameMappings=NULL; . j. y# E1 H5 [' A
' U. ?+ ` E; u
FileOp.lpszProgressTitle=strTitle; : g- ~* W8 C" e) l
2 b# E: n" t6 r" ~. U0 K nOk=SHFileOperation(&FileOp);
+ g; }. Z# y9 ^5 Q5 P4 U: g6 q - D' n3 T* J( Z2 q5 \
if(nOk) |3 a3 q3 X- u9 n, G
2 ?+ d7 h- o, \( ? TRACE("There is an error: %d\n",nOk); $ k/ q# d& C& G; t& W
z P- `6 o1 |7 U/ d0 H4 l else % H9 r% E- W" C* }& q8 P5 v
& C* o- h: `( N: y* P7 O TRACE("SHFileOperation finished ! U, ]8 [. \% D# o( A' c1 r" R
successfully\n"); # v0 @; T( d ^* _! z
: b4 ]/ J* _4 }, g+ t, O if(FileOp.fAnyOperationsAborted)
- z" }/ W% a5 I+ Z3 u5 X . l7 w" y1 o+ m! d/ q, L2 E
TRACE("Operation was aborted!\n");
; e0 F! D3 j) y1 o' J& w }
1 F6 P, W9 Q: w: t) l- m / V& M$ [9 v9 W! i2 L
( D4 P7 `0 z) n9 p
三、 结束语
& b j& p2 y3 h% D. |) k) c6 G, l4 s
4 r3 A$ c% `/ e& F---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 ( _" k$ j/ P$ i
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 + v# z6 j* Q' V3 y+ O! v3 B
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 0 E8 y$ {% ]# L X" C
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 ) a" U7 D# j7 g. Q, `
5 n# s% S$ `3 ?3 G7 {+ C0 R---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
# F& z* i& o: X; m, L2 S到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 5 l9 @' E2 Y2 h s7 q- Z
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |