|
6 w8 E+ Q9 Z- a( ^; V9 {: W! \: G湖北工学院图书馆计算机室
6 t" ^$ A* ^' P9 W6 y, h/ M张明武
: Y7 \# A H: t& \, n 5 D7 v3 n* e7 ~; k4 w7 K
---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 * F4 W( A, J3 W, Z8 u
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE _; y$ f0 Y& r6 a- c
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲 ! l0 J% v8 E/ M6 u' z
区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据
) Q- p) G W& m# `0 ~- l: c& b库进行备份,很难达到最佳效果。
, I1 R1 i* R% W% a+ _4 M
: y0 x0 A9 X; J. y6 D---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实
0 ?9 U/ ^) {8 D2 e现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 + T& E8 T1 `4 W8 T. d% m
可以直接对一个目录或目录树进行操作。
( e3 E: [; r, k 5 s2 q+ b- y; I) G$ [
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 / q: t7 \3 |& q5 `* T& D9 ?
文件的拷贝操作。 ; u- P% |5 V7 ^) r; Q& R7 G& j
3 w* r* f$ D( a( T' e1 ?一、 原理与结构
# g! ^" R# I1 A4 }* J
~" U0 r4 ?% a3 E) m---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向
. y0 v T8 U' A7 Q* C3 fSHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下: " K" I% U. U, Q) z8 P; @+ H
9 o( k* a# u8 X* i4 I9 e3 ~---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT 5 C+ M! H0 c! e: o+ J
lpFIleOp); & S5 v8 u/ V9 e
7 m, u9 M3 F; Q* Z n
---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 9 N' h! _4 n# E+ n
下: & r/ q% ?: D: Q5 Q" _$ Z" \
4 t; j& A7 V* C) _. K, r
Typedef struct _ShFILEOPSTRUCT { 0 R! N8 b6 b" c3 \/ h
, b9 B$ y8 V& |5 d1 v* `8 k U) q6 b" g
HWND hWnd; //消息窗口
! ?* U t1 E* u' |* p- x9 O, g * F2 E% h5 G- M
UINT wFunc; //操作类型
4 g' m" B4 b2 e( W& @. m9 s
0 E2 X; n0 o( K( l2 s) K2 A, n2 w LPCSTR pFrom; //源文件及路径 # b, m4 F7 u& G C, P
1 J% J: _- v, L6 f. k: j
LPCSTR pTo; //目标文件及路径
8 E* {6 i8 w# y* g 2 _3 _, C' N! J0 p# O/ b/ A0 I
FILEOP_FLAGS fFlags; //操作与确认标志
* P+ M& }& j+ P+ q3 U6 b
' X5 Y( m5 Z/ W& M0 A BOOL fAnyOperationsAborted; //操作选择位
6 ^) k0 v& c- Y' B& _
( i( [7 q# q w2 k& F LPVOID hNameMappings; //文件映射 ( m) [' C% k+ ?
- ?& Y8 k+ r+ c9 ? LPCSTR lpszProgressTitle; //进度窗口标题
% k# V& K* C( z& k. E8 [7 ^4 E9 T1 R - y/ M- J: s' p3 h) C2 E
+ y" ~% a! s% L2 R+ f
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; 8 R+ q |3 a& o3 Z9 ^4 O1 a
& o2 }3 c" i& a1 a$ a- [' c, H
5 u" q& X$ I6 ]) q) J8 G% ~
---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
/ H7 C' h: W. g3 K' V与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个 - m: _! D) w% [3 r3 v
文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 0 m5 u( p. k+ `% r4 K; S+ u
个,则应是: % O' {7 R/ Z2 b5 r& ^1 D: ]/ G
% n. J( x/ I- _+ P+ T+ e' ~! p char pFrom[]="c:\\windows\\command
; [8 s: O; w2 x' S/ _4 _ 9 u/ c/ A# p( r2 ~7 K$ V o- {
\0c:\\dos\\himem.sys\0"
) d# }! o6 ^5 S# f5 ~! n& ]$ e! e 4 ^. d8 o0 ]& O0 U, I
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
) {" U5 a( w* n& G- c( p进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
& p8 z! @& o% j9 T4 S* V2 f要成员,它指出将要进行的操作类型,是下面的操作类型之一: ( {' K; Q5 F% O e' l$ P) |9 @! \
4 ~5 \! _9 L9 a4 { j% |* ~ ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
8 s: E7 W1 G. V" W; U1 S
2 G, r9 w" M& b$ @ ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
9 `$ Q& a. i; Q2 b3 K% ]; A } L2 j # N1 f/ j+ |/ |6 h# l
! l& g- n; y9 n6 F7 a8 `& N+ p
---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 8 r0 v7 i1 W. @
3 I1 j; }& N' R7 P. @0 y ---- FO_DELETE: 删除pFrom指定的文件。
) S, z* S2 L9 x9 W) N 5 e+ q6 C2 z+ e* V7 Q$ F8 q; ?
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 3 ~) K) Y' o! s. F! M! `
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 - W% d% t+ H% s( i/ Z% f0 U
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是
! X) t5 _, @0 u w; c在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
% b5 T0 Q+ ^4 ?6 ~; B0 T: I$ D组合。
2 W; o+ K8 H4 x; J8 h; `' R; e) b1 A ' }2 g, O3 A. s) s! _* N, O! c' c. G
---- FOF_FILESONLY:不执行通配符,只执行文件.
2 w: _6 {9 Z( x/ p( R" }& j
" \1 o9 ?8 Z# c& L ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. - w* b# i) W0 u+ w
8 {; i* G" |5 K2 R5 `8 p: t ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
2 y; |& E! p8 }# Y: Q7 x候,如 . g2 Z7 p! V. `8 n
果不设置此项,则它会出现确认是否覆盖的对话框,设置
; w! g# p; A2 o* x2 q; b此项则
3 g& f0 _) \ F/ b 自动确认,进行覆盖,不出现对话框。
1 T8 a' z7 _, B" Z) m/ [6 j+ x
+ A/ A: W3 \- K. w6 w& v5 Z ---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出 ) W% _) e- c; }1 T! b9 B
现错误
/ M& R6 u) I" ?2 Y( @( ^& N: W 时,不出现错误提示,否则会进行错误提示。
8 c' P6 [" ?( ?; Z& j ; I U' V; q# K& m* K
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
- L; d% Z8 W- M5 X0 [$ Q: N/ y进行更
7 m2 J( ^( e) v" s 换文件名提示。
; g5 }. o9 I( `& R+ H- Q5 ]2 t
; W1 q; g* g3 q5 a1 u' k ---- FOF_SILENT: 不显示进度对话框。 7 n. T: {, O0 e- @
/ n+ b2 O3 i, G' ~1 N$ u4 ] d
---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
0 I) j) ^# ?+ p函数返 l, l, v% D e
回正处于操作状态的实际文件列表,文件列表名柄保存在
; k0 N' }. @( ]4 N: W 2 E" `* g) g+ {5 Q3 {$ K7 I
hNameMappings成员中。SHFILEOPSTRUCT将包含一个
7 M7 o7 K0 s: L8 g- M2 c SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每 0 f/ A, [ ?, e6 P W& P) G
个处于
0 z2 n1 c+ J6 }% S$ O 操作状态的文件的新旧路径。
* `8 k8 N ^1 a8 W! ~; D* O . g# {( u- ?$ c5 V1 A
二、 实例操作
1 O/ r! c, A: ]! j+ G* `4 d7 }
" h$ k4 n, y% @- T---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 ) [: i' Z. [- U8 x8 z( d9 e
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
. P- m: |" L, S) q$ W+ x. O工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. 0 y/ ]8 l4 B: g; }, y" ^3 X
cpp的OnCreate()成员函数中加入工具栏。 % r# T" `! v% w' M3 D
* R, P3 e" t/ l% s# S2 K% j if(!m_wndMyToolBar.Create(this)|| - K! E" x9 p, v( ~# H* ]7 w1 {, f
4 ]( y0 z( O7 ~
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))
+ _% u0 p& I G2 w 1 [5 z/ H4 S5 {3 a7 A
{ * d0 |- |( F0 S5 P9 p8 ?
$ @$ l( h- @( V5 q& U8 h TRACE("can not create the FileToolBar!\n"); 3 p7 A+ q+ c/ v* Y" H
* x' X8 u, F4 @6 D$ m; m9 e , X) g- f5 ~! w' x
return -1;
! Y/ M1 \7 ^ j( F; { ! Z5 o4 [$ F5 b: g: ?
} " z! n" o- N0 |- ~$ y% x1 H, p
3 n5 w, f$ j& F) H. }) M
7 l: n3 N9 @/ k4 v8 b6 R---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
; J. R7 N, o! ]4 UID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。
4 f5 {7 a% [, T3 U, G
* F, W6 Y3 @8 P6 L void OnFilecopy()
$ X: n D+ g' V3 m4 n {
6 g% q# c+ e3 g/ h int nOk; 8 h$ o: n2 }# w
char strSrc[]="c:\\dos\0c:
' I* T7 c% X# U+ h\\pwin98\\command\0";
$ {2 w& [7 u" A6 s: I: s. n //可以改变源路径
- x7 V. M) v0 Z- I# r+ D
: \5 R9 n3 h( z5 W8 }. J char strDst[]="c:\\temp\0";
! x: V6 |6 f; R3 t# ~: O$ f1 d# ^ //设置目的路径
' }* k; }& d& v) j
* W n1 U% F" S char strTitle[]="File copying";
/ k/ p8 w3 M5 Z, H$ O //进度题头
7 J) y. |" f% d1 O5 j : ^6 \; O4 ]) V' G! ^( Y
SHFILEOPSTRUCT FileOp; 8 m# | Z/ k% L+ w( V
. H0 N2 X& p2 O. E% i/ U FileOp.hwnd=m_hWnd;
' b% v! j) b' q5 h( @# R
3 e0 p5 s. R4 }$ o& l FileOp.wFunc=FO_COPY;
+ _ V$ S0 b$ L; k/ A 5 ^/ u5 W3 u- }8 h5 ~
//执行文件拷贝 " R+ k: @( V4 ]4 |" C1 f0 y
9 z& s/ j1 ^& \. q" ?* K% `
FileOp.pFrom=strSrc; 4 |$ ?0 p; Y4 S& l2 Z0 h' p- I
+ b' S- z- F2 y3 L: { FileOp.pTo=strDst; ) {! I$ R" e. [7 n1 J8 O
; {% Z( R: W" e1 X9 q" n FileOp.fFlags=FOF_ALLOWUNDO; - B9 m3 `3 h8 l* g. G
2 u9 K* u* V4 ~( m% H1 c. D FileOp.hNameMappings=NULL; . B2 h9 j" a* V$ h* \6 ?
& a5 U! F! r$ p% @& A# F
FileOp.lpszProgressTitle=strTitle; ( V( G4 x( D8 O& ]/ d6 w
" E5 c8 m. {4 }
nOk=SHFileOperation(&FileOp); & v3 u7 ^7 V) J P1 B, {: b. {
, K; i3 o$ T' x8 d7 n* q if(nOk) 4 y; k2 |" ~( h7 D7 r
) ]0 r9 |( w$ T0 h- A
TRACE("There is an error: %d\n",nOk);
[6 M0 _) \5 L3 K
/ o+ k4 f7 r- j( z- i else
' W$ h2 d5 ^# X8 Q& k9 W* n
8 h% W0 v! a: S3 u3 F: n TRACE("SHFileOperation finished + Z) Y# u" k" b8 |# P8 _! r
successfully\n");
% z I2 S* T/ o% J! p / G- `/ t$ U v; R& ]
if(FileOp.fAnyOperationsAborted) % b6 r8 \! i {; ^8 Y
1 b5 |; p. }9 o& T' A9 V TRACE("Operation was aborted!\n");
" r" g \& Y7 y$ K5 j- p }
- M7 N: C* L5 S! a . ~9 z; b3 F2 c6 H0 X
; A, Z& l, G4 H, O' U- v7 `2 u$ Z8 o
三、 结束语 + Q3 w: z9 M' ?* a! N
3 M# P \6 A5 \% O% E$ H' |
---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中
6 |; C7 A1 y& Y$ z1 w的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 ( {3 F$ c" m5 D$ g0 g) w
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 + z) a* J8 a0 \8 W1 ]- l* s
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
# S7 j7 O' T6 x6 A& r7 c 4 Q- _ |! _8 \0 ^8 i+ G3 d+ K
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
$ V6 X; a {; ?$ w% p5 [6 `% d到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
. a% j/ I- w& C6 n( N4 f) O9 n地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |