|
2 c P5 T: Y. G
湖北工学院图书馆计算机室
& G: h2 M! r \: w' w/ O张明武 & T6 L$ L4 M0 j* C# ]1 {
8 `! p6 u0 K) A/ U1 ?---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的 ' h9 {3 m' V3 D0 |5 K
操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE
% ~/ K, g- ?6 v3 c# p! ?! Y$ e2 F、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲
1 e' ~1 l/ ?! b1 h区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据 , F) |7 l N8 b6 ]
库进行备份,很难达到最佳效果。 - n4 f, C1 [* p7 {/ k" J8 E
. Z) ^1 h" Z3 d. [---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实 0 {, s& D# \/ L2 ?9 c0 X
现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也 ' M! A! O+ w4 z) U. @$ h
可以直接对一个目录或目录树进行操作。
" Z) ?; v5 _/ {& {' ?1 e 2 `+ ~" ]$ m! J- F! ?! ]
---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现
. c2 W& G( N) Z9 o) m文件的拷贝操作。
- R' \9 |) S2 N9 X m! P
* ]( H9 t* ]: j$ F' [; J9 S一、 原理与结构 L! ?! d8 a) t) K% V
$ K7 c6 f* d+ Q l2 ~7 m: Y
---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向 . h0 ^ s0 x+ H) R) P; B
SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下: 0 K. a0 @' P9 [2 V* w3 M
' h* h# k/ C- Y! o/ _8 v" ]---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT * M( l' @# |9 k6 F+ h: ?* F$ y2 h9 r
lpFIleOp); 0 b) e, Y" ^- G" O2 b2 a
7 I, q7 R& ~* Z; v2 a---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如 7 D( N% {, g, L: @3 Y
下:
. @: r" ?/ ?( u0 B, R
* M# _; h6 X5 h2 ` e& v* h, W Typedef struct _ShFILEOPSTRUCT {
9 I5 K, W( ` S0 [3 \ % S% w1 D" c& G M
HWND hWnd; //消息窗口
, m* u2 `/ k* T7 f
3 o7 Y0 c0 e. V$ _! r UINT wFunc; //操作类型 & a. `" Z% ^) u- y2 n2 }* \8 ~
% r: r8 O' g3 e. I0 m
LPCSTR pFrom; //源文件及路径 2 r4 w% y7 s" }+ n
4 ?( @5 t0 {; W/ n: c# M1 C
LPCSTR pTo; //目标文件及路径 ! l+ K: P7 u' w* h* G
. \4 a# X! }) u FILEOP_FLAGS fFlags; //操作与确认标志 ( P3 `7 Z- ~2 y, ~
8 W( p' \6 |: z
BOOL fAnyOperationsAborted; //操作选择位 ( B) ~* m6 P. _# P* D# p8 n
, \6 g2 F9 z4 U, f6 K8 ]. d) w
LPVOID hNameMappings; //文件映射
( O2 \, X9 V/ v D! f% J' I( e5 Z, k8 I$ P # |3 l( f3 H) R. j$ k' A# ^
LPCSTR lpszProgressTitle; //进度窗口标题 8 ^8 X- y, P$ h& G+ Q1 j3 p5 I! Q6 j
# Q% s- T+ y3 K y/ }0 _! E ( R; T( K9 I) k- l- U) y/ W
} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT; 2 R% G' c/ `3 y$ J1 s! c x
6 X* ^6 |7 Y" O4 o$ U
2 i( b9 z! a) P& z9 @+ U- ` ---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom
2 }9 C& Z- `3 @, j* V4 ^# f; f( y与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个
" f z/ K1 o( m文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两
- b0 b) |# |# _, Y4 o+ S& |3 V个,则应是: . ?& l# x' }: U) t ]3 O I6 J; r
5 K8 N0 p; {5 \0 l! L
char pFrom[]="c:\\windows\\command ) C6 Y; A9 J i
+ M# f- L3 J8 g$ l/ D% ?4 X; V \0c:\\dos\\himem.sys\0" # n" x M D1 u
& L3 ]1 i8 ~! d1 s* t4 j
---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件
4 x9 U3 J9 G- m1 {% R进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重
! m5 a0 J* L* S2 C4 B5 S# |4 {& E/ T要成员,它指出将要进行的操作类型,是下面的操作类型之一:
" n0 V& u; {) U" c" s
( I# D' T" ~$ A9 e+ s5 t ---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。
2 W0 j2 S% k* m6 Y7 h2 N2 h& ]
5 Q" U& A6 J7 J; J u" m ---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。
. b; |# l. [8 Y# G" H% b8 k
) t5 Y6 z9 g7 `8 H& M
5 F4 N ]; Y5 j% s+ F2 k ---- FO_MOVE: 将pFrom的文件移动到pTo的地方。
# i1 B# {, l Q& U& f6 x- c( _ , G7 `& x( l$ p2 u9 M
---- FO_DELETE: 删除pFrom指定的文件。
% O N( a$ f6 ^ - p0 i v% ]6 z2 j; g8 R
---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过 0 k" p2 {2 \* B4 E4 O9 D
程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝
8 [3 ~. c: K& i8 b& O3 y移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是 / a3 i' B6 g2 z& a* D0 v0 P
在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其
% {* [+ d! C4 S$ x7 l组合。 / W/ o9 V) r# W) A, f% w0 z9 a
* M: x( {8 |5 I! y5 | ---- FOF_FILESONLY:不执行通配符,只执行文件.
+ J8 p0 P. @3 {8 \5 ~. |
! I m0 Q1 ?' @ ---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复. 0 O5 F- { { t4 g3 m
( Y) E, |4 ]2 B& P- b ---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时
+ J6 F0 I/ S2 P. T6 L" O候,如
2 j9 F) _# ]. x% }& c1 I1 k 果不设置此项,则它会出现确认是否覆盖的对话框,设置 ) X$ |# s3 \& e$ P, H
此项则
9 B1 ^9 m, K" @+ E' q4 T1 T 自动确认,进行覆盖,不出现对话框。
2 {5 K- ?" n7 u: \: b( e% ^ 7 ^* N3 a3 o3 D+ [ y3 F
---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出
2 ?9 M! w+ m1 Y$ l6 p现错误 1 f2 r, I/ W4 S# D. v% Y
时,不出现错误提示,否则会进行错误提示。 0 A0 @3 [4 P7 m$ C5 W
# ~- A z8 K: @ y ---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其
7 ^! r' i9 a4 K5 w. _2 L* ~进行更 9 Y9 e; G, | P- b. i. p
换文件名提示。
8 P( a6 W* i( p7 Y! E8 N( ] O
. G4 C8 L# D3 K$ D0 F ---- FOF_SILENT: 不显示进度对话框。
* ?( O- Y* ~2 u
- v9 u& H3 e g% V% u* N0 H ---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()
5 i0 q) o" U% h3 h函数返
2 y- G: y8 f, e4 ~0 `7 y 回正处于操作状态的实际文件列表,文件列表名柄保存在
' U6 s- G! y& A$ m0 E' u0 P( X+ q
0 j& C9 [ N ]+ [7 P hNameMappings成员中。SHFILEOPSTRUCT将包含一个 7 }: L2 P$ u" s4 i; R
SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每
; K" y$ F0 }0 H6 H, s个处于
! _/ m% Y* S3 u- l3 G 操作状态的文件的新旧路径。 3 }! `5 e+ J! W% b
$ K4 N; {% f; ?4 V( i3 F, U二、 实例操作
8 e3 Z4 X% |9 g
$ k1 i' E. @8 ^" S. m---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档
5 b& h7 a3 Q4 J( ~界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个 * ], a# v; B/ v& C( w' M) i# E
工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm. * v6 M1 r8 h9 q% j0 | f8 ^' S+ {
cpp的OnCreate()成员函数中加入工具栏。
5 z) Z5 d: @- b# b9 I+ k* o' J / c. N, s/ ^0 \' Y1 D3 S
if(!m_wndMyToolBar.Create(this)||
5 z+ `/ K8 k! f' Z; I ; e% {; I4 I6 C
!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR)) * A( r# ^0 R/ h X" J2 o
- c, g, r9 x* m2 i6 p
{ % E$ J) `7 U5 }, c4 ~# N
2 Q, `& D- h" S: B' d9 ^
TRACE("can not create the FileToolBar!\n"); 0 F: B+ V# `% i. ]4 O
+ Y" N. a+ ~3 `0 A- W
2 Q9 h, F1 I4 l( B return -1; ; ~% ]- m/ a* Y5 e
2 q [) Y; H& w( M" v) Q/ L2 y3 [. t6 ` } # t( V8 q- p9 n9 r9 s f7 ~: f( F
^ M) s2 c K: A; y+ y1 ^: ]. d) A' R ! r) O3 Z1 n; Y, m0 _5 i
---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息
3 Q4 q; S& F' I$ O" s' JID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。 5 ^) P% T4 n: A' e5 K: ?6 @# \" A
% s2 b) o) p8 R' s0 { void OnFilecopy() 2 K, O2 v9 `3 @1 m; ]6 K
{
5 L# N8 e5 ]9 k& y' x int nOk; / H9 \" e v. ` D5 k
char strSrc[]="c:\\dos\0c:
, r8 R' ^6 G; ? S\\pwin98\\command\0";
# H- I" D a6 R+ S //可以改变源路径 % A6 Q9 X1 ]- w# L
- q" i3 b+ ~4 g! B% M
char strDst[]="c:\\temp\0";
+ @, ^ F2 j. r& _, B( n //设置目的路径
' I: l2 p- [% z2 N2 x; Q 1 j3 {2 v& e& ]4 A
char strTitle[]="File copying"; ' Z& q8 h& Y/ S
//进度题头
5 W/ @- n7 q; N8 J! G4 M+ z : j+ n! Q/ ~% s8 }
SHFILEOPSTRUCT FileOp;
& p b8 [* Q/ V( {% q8 Y8 L8 B
3 S/ R: U1 }: i7 l, a' D6 F# p FileOp.hwnd=m_hWnd;
% t u" ^7 z) ~ ; m1 v& C( B2 T) z7 a# G
FileOp.wFunc=FO_COPY; : J% L- r6 H5 N$ }$ K
% g/ ?& M' z5 T. c
//执行文件拷贝 . J+ e7 E" d9 v. Z9 D
, D0 |( O6 C! z* C: N8 E FileOp.pFrom=strSrc; $ z1 x0 s. z7 f/ U" X6 M
# ]9 c5 B3 y9 n% V: _
FileOp.pTo=strDst;
, C8 p9 @: @! j. W8 n / e/ O. k7 N) L3 I% i N5 h
FileOp.fFlags=FOF_ALLOWUNDO;
- G9 L& v2 b* P
" n, N, ?3 h9 x6 Q8 S1 O1 }" W' j FileOp.hNameMappings=NULL; 2 ^( ^% ]9 R8 k
& N _' k- j E1 c' c- m! m$ R
FileOp.lpszProgressTitle=strTitle; 4 {8 f* ^0 u! r, }, J9 M
) E% }& j% l9 S! j8 P1 c6 B
nOk=SHFileOperation(&FileOp);
3 O; g6 M! n$ J" F* W0 \0 O3 `" j! o " Z, p* B0 }% h* ~
if(nOk)
7 v8 u7 v2 H t' X! y
2 F( W2 h6 L, _, T/ F TRACE("There is an error: %d\n",nOk); . p, H0 p, [ |7 ~ G
) r2 O6 o5 C7 D4 @; o: f
else % F: Y3 N: i i7 L. W9 u
2 B) n: z9 \1 M
TRACE("SHFileOperation finished
+ k' o1 d1 ^$ ?2 Msuccessfully\n");
2 k" u K. L/ Q# L7 W( g% e; w$ b
! W! H$ @+ U, h8 J5 W% L, z) F if(FileOp.fAnyOperationsAborted)
; V. z- s7 Q1 J: \4 `* c: z! h1 G5 S
+ _% E8 W1 p: _* M TRACE("Operation was aborted!\n"); # U/ Q9 \1 \' j0 O
}
8 e5 b G! r0 \- f+ D 3 B2 x+ T I3 A" o B) f- Y
7 a& q3 P0 b$ K+ ~" o4 ~
三、 结束语 ) {# a& N# e, t# d
: h3 A' W& T6 E7 M---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中 & I) ?0 U/ z/ o
的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在
( }6 e' o; v% _" Q, l8 c系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调 9 E* Q1 W. h' ^; g2 _
用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。
8 s; w+ k9 {2 s% s" j 5 O* K# u" | i; y- o$ W
---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用 1 H9 Q& Q1 [; A. c1 M" r
到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步
- c# y/ S o( ^" u7 h% k! b地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。 |