|
- @4 N/ |; d/ |* {+ N: m r$ w
湖北工学院图书馆计算机室
# G% _ W% Y. _# U1 {3 [, o1 O张明武
5 D- a3 J; ?0 k" [! ~% B& H
4 R% C* k1 E) M7 s! W4 t---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的
% }0 c+ p* f! Q" E操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE , y# u% T' h" y7 f' e
、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
7 t7 R, f8 ~6 G0 ]7 p! X5 x1 a区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 9 \4 A/ L. w2 V: @" | e. A( N, l6 [
库进行备份,很难达到最佳效果。 4 d7 F) p' z$ ~3 e4 b
; P; B( {. t( E! z, V---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 / d& Z [0 g* G1 K
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 % h/ p4 x6 `' O8 b% F
可以直接对一个目录或目录树进行操作。
- G: G* |/ Q1 D) y 6 E7 ~& b M- y- P* p
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现 " y' ^8 i5 Y# H
文件的拷贝操作。 $ b7 R5 ~; p, `& Y B# k" z
; o: D2 C4 R9 |$ R9 _一、 原理与结构
2 q6 r1 z& l3 `8 |
. ^3 G7 F- T1 J! O: K& I' a---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 . }# F% N8 i; B+ ], k
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下: , w% [4 n6 P1 q* C
. j- Q% y; m ?$ W3 j$ t' |0 O
---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT : w$ e$ H: ?5 k7 p1 R! }4 S, m2 U
lpFIleOp); . i! E; f- q- y, O& S% W* a. q
( _/ z/ G# S" K& A' ^; _6 ^---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 ' |+ K9 l/ V/ f
下: 2 }) p6 R, z5 m _
/ K S& V8 c& y7 L4 s4 @2 U" L Typedef struct _ShFILEOPSTRUCT {
7 J, J$ Z# a7 H0 z3 k- ]+ Y" Z * O; P+ }. t$ k8 A
HWND hWnd; //消息窗口
6 {) e$ F" k: r) @& O $ s% h8 e3 \6 k8 u6 m4 o6 }0 m* B1 W6 b
UINT wFunc; //操作类型 5 A6 u4 i( h9 P$ ]& s9 c$ C
6 s. d/ b1 \- p; ^
LPCSTR pFrom; //源文件及路径
0 w$ N$ N2 {/ Z" f: T2 S
& d7 D- K& h. Y# i LPCSTR pTo; //目标文件及路径 S7 k3 q" r5 R1 N; n/ O2 ~
4 p& k/ r' Y ^# \
FILEOP_FLAGS fFlags; //操作与确认标志
+ G* {: k+ R( f2 i& E0 L7 [& S/ |
$ ]' v4 u& V' _7 |! @" Y BOOL fAnyOperationsAborted; //操作选择位 ]. D# l5 s& i6 v4 U
8 c, t o& c9 T+ P5 O! m! U4 ~
LPVOID hNameMappings; //文件映射
4 a! X/ b5 P d$ F % S p: \, ^7 Q5 c- i
LPCSTR lpszProgressTitle; //进度窗口标题
% B0 G( N8 _& K3 N, A9 V! H u( [
, H6 t& v/ T0 O0 M+ I1 Y
/ ~! V) C/ s! i) f! x } SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;
* U Y' R# n" E- H6 ~! R- V 1 N% c7 |6 H2 L! Y u( ~
0 x- g% I: y/ d ---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
& E. y* N' G- T! h5 T* I与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
9 h4 l8 m& s; ^文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两 5 m, w1 n: }4 z9 T- @6 C
个,则应是: / _) X; F, R, I. Q
, T8 |( K5 ^, N6 V
char pFrom[]="c:\\windows\\command 6 T0 [' Z3 r: R, `
* f: X& ]0 N3 f+ E \0c:\\dos\\himem.sys\0"
6 K* n+ H/ I# }9 \! u: Q3 t. | - L0 _4 f+ Y8 A" D: H: A8 l6 l
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
1 E: }! G* S- q- [. S进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
/ R# t5 s- Y% ]& `6 t要成员,它指出将要进行的操作类型,是下面的操作类型之一: * f5 z6 @+ x( ^6 |$ T
7 {+ ?+ W& f0 j* F# V2 I2 ?3 B+ I ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
4 v+ Q$ T m; G
3 D/ G) m9 A M% Z, f3 P. Y$ z ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。 8 U# R! [# x! }" r& f
* E+ D9 L0 }+ U! p: a& M
! O: J$ ^; P+ V5 c ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。 9 {& }% N( a2 R# J1 X; z' M
6 _3 X0 f2 D5 O. i, J ---- FO_DELETE: 删除pFrom指定的文件。
( T, J3 K, W- v) U* J + Q" Y( x+ C: M; ^
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 7 n4 q7 w( E, T0 [" ^& ?
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝 5 D- N- o1 X" [/ Z5 R& P3 ` T
移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 7 o( f; T4 x- C. ]
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
1 w2 c( O% O( L# `' g, w/ {组合。
3 k7 d6 R5 L5 P' @ 5 j2 X1 N& U0 \2 i
---- FOF_FILESONLY:不执行通配符,只执行文件. " D& w0 {1 ?7 B
4 P9 U# p; m5 k/ x( c6 \9 S! d
---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. 3 G) V8 d" \3 [( B
1 D1 i: }' E. I, `! u1 g4 u5 T
---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
0 t+ d) v3 i1 U$ @' P4 C候,如 + y F( m' g: N3 _
果不设置此项,则它会出现确认是否覆盖的对话框,设置 % t" G1 |4 O8 S) F
此项则 ) j% N: |0 f2 ~- Q
自动确认,进行覆盖,不出现对话框。
6 O2 k8 U9 ?/ z9 i& o+ z+ ?; X 0 f( N8 q# s6 N( c& _
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出 " }( S/ q1 @/ D1 [: t1 S3 Y
现错误 K6 C+ ]$ ?/ f# l8 t
时,不出现错误提示,否则会进行错误提示。
; m. \5 C m8 I% q$ r5 R% C 8 k) q; m/ ?* v+ n
---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其 ' p% T/ N! f6 j$ l1 {9 P" M- ^
进行更
2 S; f' U0 a9 S/ Y, I5 V 换文件名提示。 8 z& G. g' M: |* i: D" j
, ^+ v1 _( g; b% a ---- FOF_SILENT: 不显示进度对话框。
" {% s3 P; }0 L4 d5 f- y+ H& x
% q9 p: Z3 w/ g6 q1 [% _ ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation() 5 X9 F8 @2 K* w2 d4 o$ `
函数返
' l6 `" h6 A% l1 k! G/ t# @ 回正处于操作状态的实际文件列表,文件列表名柄保存在 : X" c2 a1 o$ N3 E) ^# g1 @' H
( J$ l) i, \4 R+ W3 P- C) c" d/ w$ q hNameMappings成员中。SHFILEOPSTRUCT将包含一个 2 \- P3 v Y. `3 `) M; X" O5 o
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
, e* [' ~/ P. i个处于 : h- b% h5 J% w0 ]) q
操作状态的文件的新旧路径。 ! E& w1 |, B8 j9 y8 ?
% o; M3 B0 r( P; o
二、 实例操作
N1 P) L V h# a! }5 W6 t
0 E! U. }7 ]+ X---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档 " U, S! x# z8 `( a' }
界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个
9 u+ j% A1 |( f) J; Y) E# l工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.
9 F9 ]8 |3 S6 u6 J( \1 ecpp的OnCreate()成员函数中加入工具栏。
2 A! B) P" r/ ~3 p% x : J% t% U! p7 q) r0 F% }: C
if(!m_wndMyToolBar.Create(this)|| - m0 K6 y5 p% N
. p1 C" S! p5 b8 r2 y
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) 0 l! L) s+ O) l# x$ b
! N% \4 l5 ^' Y, x: W: O {
1 }9 h2 M! P! v6 M+ z n
1 b; |/ X5 b; f0 y$ d% Q! U/ I TRACE("can not create the FileToolBar!\n");
- d8 u; D* t0 d) v # h! a1 B3 [' N: v1 s1 `5 d
$ D- E( J* P: \7 U" w4 c- l8 s% h
return -1; 2 s, r! M3 m; r2 {$ S. p/ z+ p# w
4 N8 ^& Q4 K# O* K! m' k- ~ }
; l$ E1 F, t, H& L' e. N! }% C T- H2 }5 G' t& r
6 g; }: G! M- c; d---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
! g6 Y8 M% O8 I O' R' d7 r1 ^ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 1 r, O& A7 A ]! u
% V9 h l) E- G9 @8 W' U
void OnFilecopy() $ s1 b. e/ L- _ e- Y7 c! u
{ 8 U/ v# f$ s; w" ? p' F, U
int nOk;
. A! C7 r( f, p5 q char strSrc[]="c:\\dos\0c:
1 r% U# ~: \1 K2 o1 n\\pwin98\\command\0";
$ w, k6 y8 s/ R" Z //可以改变源路径
. c0 G' |% h4 W 8 d. Q6 j: H" i
char strDst[]="c:\\temp\0"; 3 [4 r v$ P6 h' w3 }2 A
//设置目的路径 % I9 K$ d- g' b9 N) Y8 K7 n/ v
6 U8 _* X; ?. H
char strTitle[]="File copying";
" Q% b1 j" u( ^- r; ~ //进度题头
% b0 t4 k0 r! x5 Z
; {2 T, S, k1 T: q SHFILEOPSTRUCT FileOp;
7 ]3 G1 K, `2 }+ D ( D$ R5 ?& U! \# T3 c+ b$ c! y9 J
FileOp.hwnd=m_hWnd; P1 r( L+ u& w# m$ n
; o: u; I5 e% w7 Q# }
FileOp.wFunc=FO_COPY;
0 I/ U' q* |7 S: p% o ) `6 r4 z8 v2 ?* S* S) x* e
//执行文件拷贝
! H N: Z1 B7 S0 w. q% E ! S( r3 h! a- S6 v
FileOp.pFrom=strSrc;
0 y) E" I9 ^/ k. g , ~3 ~# w8 n/ v9 {9 |
FileOp.pTo=strDst; 6 y6 K( {3 N( W, w
% E7 g* X6 G* j1 M
FileOp.fFlags=FOF_ALLOWUNDO;
9 F0 c3 k( f+ w$ `2 l+ \
! ?+ s" ~2 n% Z3 d FileOp.hNameMappings=NULL; . n) M+ ?4 r' @1 `
5 y- [8 d6 ] t# D# K FileOp.lpszProgressTitle=strTitle;
9 }7 ]9 y- G+ q2 G# M- H% v
& J' G3 c, c7 y1 w nOk=SHFileOperation(&FileOp); K* l. \7 C' s5 F; `
/ i5 a3 H2 E- T( j4 x: @- a7 E9 q/ A if(nOk)
% n, U* g+ i' q0 T# g
5 P' G9 G' u: E3 X1 d e& G TRACE("There is an error: %d\n",nOk);
- _% B- d9 `2 ?: {
# A: o& \* V. X/ u( D8 p. U$ L else
& c6 a% `& r- K) b# V9 _7 {
( g ?$ k8 P g1 k9 B* M TRACE("SHFileOperation finished
0 R7 x; k1 h8 Psuccessfully\n");
- Z L2 L t) t" X2 @7 V4 x
, Z4 m) e$ v/ p* Z if(FileOp.fAnyOperationsAborted)
" ~6 j. |5 ?6 F: D3 H& k , ?! I" p8 [# e5 Y A2 x2 W8 _2 K
TRACE("Operation was aborted!\n");
* m9 j7 e# v/ a8 b. ?" b }
( }; ^4 V+ C: T* T
" n& O# f% i5 s( Y0 u1 q : u4 h0 G& P2 Z H
三、 结束语
2 N, D% M0 E8 t. P
: D2 M) ]: l6 h6 a---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 3 I! m# Y% _ X' p
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在 2 H- r# Z, ^1 H
系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 # u( P( W' a( `: A$ w% R
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。 " }% i i3 ~2 E% L- N! v
r% X4 X4 B( k. x }
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用
7 X* m; |: d5 N到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步 : `; Q8 x n m' M) P
地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |