数学建模社区-数学中国

标题: 在WIN95中实现文件拷贝的编程方法 [打印本页]

作者: 韩冰    时间: 2005-1-26 01:29
标题: 在WIN95中实现文件拷贝的编程方法

) \4 P3 h4 u: O/ P t @

湖北工学院图书馆计算机室

7 Y, E _6 c! |2 \% o1 x [! |/ R R

张明武

9 R4 j Z% ^! X3 |5 V

; Q: q% t9 I+ \7 f

---- 在Windows中实现文件的操作主要有两种方法。一种是直接利用CFile 类的

q, ]: _7 G% U0 o+ V3 ~- C: e9 f

操作成员函数来实现,它要用到对于文件操作的底层操作方式,如READ、WRITE

8 _7 p/ O3 y) A! u/ x2 t, x8 k

、GETLENTH等,并且要直接操作文件的属性,如创建、读、写等;而且,其缓冲

# G- c S; H- f9 N/ J

区的设置对于文件的大小和不同的计算机是不同的,特别是对于长度很大的数据

. Q: g- @6 W K3 |$ ]. ?- K/ S( \

库进行备份,很难达到最佳效果。

" o0 a3 e& N8 V+ P+ v, W/ W. |

4 n. {! d, n# M) k, l* S

---- 另一种有效的方式是利用Win32外壳来实现这些对于文件的操作。它可以实

6 {6 g; g. F4 [( V% ~. d. a

现包括文件的拷贝、更名、移动及删除等,并且可以支持通配符(如*和?),也

& Q& f! R' [. F- s3 D1 [

可以直接对一个目录或目录树进行操作。

4 x1 `9 h# d s8 M( L, b

. e' c9 r/ k2 T( b5 X

---- 本文分析了Win32外壳API对于文件操作的原理,并利用Visual C++6.0实现

& R; k- O0 E$ ^

文件的拷贝操作。

0 U/ i1 |& c9 w4 j) `

: |8 j9 ~2 ?' o

一、 原理与结构

( [6 L* e. ]% s

7 @7 {( }1 t& @' Z) F* P5 P4 a

---- Windows95/NT中提供了一个API函数SHFileOperation(),它只有一个指向

7 e' N. B/ ]' y+ x9 l

SHFILEOPSTRUCT结构的参数。SHFileOperation()函数的原形如下:

4 H$ c! {. l; i$ r" L0 f9 A9 a: N

- `4 [" k$ ^ Z1 c1 [ A

---- WIN SHELL API int WINAPI SHFileOperation (LPSHFILEOPSTRUCT

$ l# ?9 O% f+ f3 p) q" U( G

lpFIleOp);

6 h( u4 F" q- Q. \0 H" d

$ o$ p3 k/ z1 l( U/ d

---- LPSHFILEOPSTRUCT结构包含有进行文件操作的各种信息, 其具体的结构如

$ u; O/ G1 z# a9 F, v

下:

! {1 V% C9 k( L

( m! r- O% a$ l; d) [6 ^

Typedef struct _ShFILEOPSTRUCT {

( v3 r5 Q1 R; ]

O( Q- b+ J/ V

HWND hWnd; //消息窗口

9 T7 [/ u/ h- ^) }& U

( ~7 P& l3 V$ _; t* X& W) t' L

UINT wFunc; //操作类型

: R3 k; C* d; C/ y1 J5 |0 T7 H

4 m# o, G( y. A; J& ~

LPCSTR pFrom; //源文件及路径

# X% f$ c( b+ ?" B

# `6 S6 c; T% n( O; Q/ D8 N

LPCSTR pTo; //目标文件及路径

' i$ L3 [, z3 K2 v. X# y/ D$ ?) Y

8 l& A k2 R+ e, t) T

FILEOP_FLAGS fFlags; //操作与确认标志

( R+ o/ M N6 i: a7 M( U

/ k0 Y& ]* s8 H) Y$ Q! r; @8 k

BOOL fAnyOperationsAborted; //操作选择位

" `; H8 y0 l/ f6 V- i- w

5 o5 X9 [: B( A$ A1 R o

LPVOID hNameMappings; //文件映射

5 a* u3 ]: ^& n0 E

; t" R }4 J% S4 t& \' n; r

LPCSTR lpszProgressTitle; //进度窗口标题

( p5 ?) f! |0 `+ [% p, V

4 v* `- ]% ^9 e

( A" [; j0 B+ a5 D1 R' [9 _2 r3 Z

} SHFILEOPSTRUCT, FAR* LPSHFILEOPSTRUCT;

% C2 r* i2 C, n# G9 Q' N! A) R% t8 ~

% l b, u: q+ P) {9 ~( `

2 m; Y' s- i: A- H9 F) n

---- 在这个结构中,有几个成员很重要。hWnd是指向发送消息的窗口,pFrom

# _9 D& F& M6 U* j8 U

与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对于多个

$ Z! \. d* @6 |! ]8 @

文件名之间用NULL作为间隔,并且可以支持通配符*和?。如源文件或目录有两

; L* u, F# A4 E E: ] r$ C/ D

个,则应是:

; [1 w+ [7 W. {3 M

8 G/ y0 V1 e1 o0 l9 k& g( V

char pFrom[]="c:\\windows\\command

' J$ h" D2 K/ H% s- }

$ w' i6 y$ L+ v5 f# F4 k5 w$ U

\0c:\\dos\\himem.sys\0"

4 `: ~- ]2 ]* m6 j" G9 i! @# w* ^, C

+ F0 a0 `# D$ f! M9 h6 k) ^* F, |

---- 它表示对c:\windows\command目录下的所有文件和c:\dos\himem.sys文件

. z, n2 {! G# K) C

进行操作。'\\'是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的重

" c& n$ U3 M/ e1 M( r: P

要成员,它指出将要进行的操作类型,是下面的操作类型之一:

! d9 q) P* C+ e% q. S; T2 U" p0 f; V

" B: X. j5 J1 S+ \* b

---- FO_COPY: 拷贝文件pFrom到pTo 的指定位置。

3 w( B1 h. C- B

8 m) W7 e$ i8 S5 I. R

---- FO_RENAME: 将pFrom的文件名更名为pTo的文件名。

% E' p8 R4 [2 R, e) d3 \0 {

" c7 _. E/ g1 f5 {) g; a# _5 M$ d

, v% c4 P/ G6 O; j* o1 X; y1 D% V6 k

---- FO_MOVE: 将pFrom的文件移动到pTo的地方。

& m- }: f! \; ]3 M! F+ z; j

! @6 B7 N9 E8 {2 R

---- FO_DELETE: 删除pFrom指定的文件。

0 N1 T3 X: K4 n/ p5 s9 I

: z4 v6 c2 ], c6 l+ h

---- 在进行文件拷贝、移动或删除时,如果需要的时间很长,则会在进行的过

# ^3 d; o& S- C& T) n5 [

程中出现一个无模式的对话框,可以显示执行的进度和执行的时间,以及正拷贝

( Z3 [; E( Y' w9 D9 X; M' T

移动或删除的文件名,成员lpszProgressTitle显示此对话框的标题。fFlags是

0 w$ U1 ^4 F; n+ [6 [# s! }

在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其

/ |- M! J: q& c' f- O3 ]( ?

组合。

J) v+ `# X' Y$ w0 n2 [* f" J: z

- r& Q, t1 ?/ y4 Q% Z

---- FOF_FILESONLY:不执行通配符,只执行文件.

9 X# D2 a; z4 S+ N# {# c) @

0 S/ d. I1 j! }. }8 j( L

---- FOF_ALLOWUNDO:保存 UNDO信息,以便恢复.

: t l8 c. d9 p7 `) u0 o+ q; M* t! L

8 d8 n) ]" a2 X

---- FOF_NOCONFIRMATION: 在出现目标文件已存在的时

5 ~' |3 d8 D- K. Y6 ?" q

候,如

" b& g$ F1 Z2 f* @0 \* [% Y

果不设置此项,则它会出现确认是否覆盖的对话框,设置

, D! ]: J! ]) E7 m1 U' W

此项则

2 d6 t6 ~' p C6 p- r( u

自动确认,进行覆盖,不出现对话框。

) k* @" f: @6 i

6 {" ]( v8 f0 X% N* U7 b

---- FOF_NOERRORUI: 设置此项后,当文件处理过程中出

' @% i. b- a& P, `% T0 I

现错误

- X1 ^7 V5 ~, ?' Z* z

时,不出现错误提示,否则会进行错误提示。

: Z# W, K* v" x* Q I; @" \

6 S, |6 a0 x( u, r

---- FOF_RENAMEONCOLLISION: 当已存在文件名时,对其

+ j' u9 r9 O' u ]

进行更

# b- }8 ?! ^* ]! Z

换文件名提示。

# [& `3 l3 i! }0 P

+ C: V: ?; q6 X" i

---- FOF_SILENT: 不显示进度对话框。

2 V1 m1 R1 X+ r( k- J7 Z9 s

+ f! x& m8 Y/ j% r# W3 D' L% n& C

---- FOF_WANTMAPPINGHANDLE: 要求SHFileOperation()

7 s% g; }& G. l) n4 d

函数返

/ ~6 I' O" ~6 D( I" M

回正处于操作状态的实际文件列表,文件列表名柄保存在

+ S" G) p9 R/ k- v% K' J0 T0 e

4 B5 N4 Y8 V$ y. g

hNameMappings成员中。SHFILEOPSTRUCT将包含一个

) N9 ?$ Z ?; C& ^3 f* D

SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每

# }2 u+ S# R$ E$ E: k5 w

个处于

8 G+ q& g. k6 s2 R, b) m U

操作状态的文件的新旧路径。

7 O. c9 {; j+ O5 x# {5 [4 h

7 t- U5 I! { T. ] F+ i& y

二、 实例操作

8 d! T- r. ?0 D) W/ _

. v4 b2 ?6 A, H5 u1 y

---- 本文就一个Visual C++程序来实现文件复制的实例。首先建立一个单文档

6 r* M6 {8 c3 X$ y* P' W- `1 {6 V

界面filecopy,然后在主框架中新增一个工具条变量m_wndMyToolBar,新建一个

$ J+ ?. \, r& c4 ~- d2 d: B" e$ N$ P9 C

工具条IDR_MYTOOLBAR,设置一个工具消息ID_FILECOPY,并在主框架MainFrm.

* Q8 x8 c6 C, y4 f$ k: \/ B* l, y3 m

cpp的OnCreate()成员函数中加入工具栏。

0 r% U. C+ }- h4 M; {, [* Y

4 B E o+ O0 S& m+ i/ A( ^

if(!m_wndMyToolBar.Create(this)||

. m+ `6 ^ Q, w' d4 |. X

0 d3 u( v7 l/ g. `- Z# n2 r

!m_wndMyToolBar.LoadToolBar(IDR_MYTOOLBAR))

# Q( i+ y6 ~' P

/ z! u* U! Y9 x5 D7 m4 M4 ^

{

M5 u/ ?4 w1 K9 l* w+ o

3 {4 i: M3 ]+ G$ Y

TRACE("can not create the FileToolBar!\n");

9 m" E/ J. C' u/ ]# C+ F; E

|+ K# E5 ]1 _7 r

/ V2 r$ e& T5 e* y/ W8 _

return -1;

! }* g, }5 f8 ^+ j& F

; }3 H" \/ Z( ^0 B6 ~$ p' g

}

- j% L5 y" s q- L) X/ l- z

/ }! L8 c1 } { k# R. R; N5 c- t

$ p4 v; q4 b Q% t4 ^( z

---- 通过中视类操作工具条IDR_MYTOOL,利用ClassWizard为其 消息

& e, Y/ D; l$ T( V+ d3 q+ U

ID_FILECOPY新增消息处理函数OnFilecopy。然后在处理函数中加入下面程序。

" H9 M5 h1 k- I

) g8 r- T1 P5 _' v( u ^

void OnFilecopy()

) J, \8 [3 ?) L, w: D+ w

{

/ P) x9 L( V/ z& Y

int nOk;

" E+ T- P; j) o2 N) a+ ^" D- `' H% {% s

char strSrc[]="c:\\dos\0c:

2 I: G- m' G5 j$ L$ W5 o! x& O

\\pwin98\\command\0";

) i1 |- P, Y3 `3 J' k( t3 q7 ~ h

//可以改变源路径

2 z, U' x9 J/ ^

5 ?; z. i; \8 \6 E3 V/ C

char strDst[]="c:\\temp\0";

6 \$ Y- v8 d: R! v, g

//设置目的路径

8 Q0 P( M! J3 z1 ?) u

: l6 Z; n" C# w/ k& A6 u8 x) W

char strTitle[]="File copying";

( u* G, n1 {( j( l, v

//进度题头

2 T. ^! S1 _3 H# ]% ~

! |) m: h( e% I! G9 h8 @4 x

SHFILEOPSTRUCT FileOp;

* ]2 v* V+ K7 C g

9 @1 B* D' U: s# x0 p

FileOp.hwnd=m_hWnd;

& v. \4 G9 @6 ^

4 k% R- q$ B, [: Y0 ~; o! \

FileOp.wFunc=FO_COPY;

0 _& A; V+ L, I# e3 w/ J" H

# l. e3 p8 n ~" W7 {

//执行文件拷贝

9 m7 }* P) i, u! K/ |# e/ o

# A! I% c9 K9 B# f

FileOp.pFrom=strSrc;

! _& I" l W; s: c

5 Z2 M) ]3 ~# o9 v8 c

FileOp.pTo=strDst;

- U; c" ]8 Q i/ _

& D/ G7 H% A |9 Q# ?* S6 S

FileOp.fFlags=FOF_ALLOWUNDO;

4 T6 N: H) |6 ]2 _. @2 v5 r

* ^5 O6 y. W. V8 Q4 U+ J

FileOp.hNameMappings=NULL;

c$ D0 v3 b1 t) R- h7 {) U9 {

Y# p( e) u9 j. j, ^

FileOp.lpszProgressTitle=strTitle;

5 W/ K& @' Y$ n2 ^8 H

3 l) p1 t( R& n4 p+ |

nOk=SHFileOperation(&FileOp);

1 Q! _( V9 i" _; {: W" r

( k* B4 O, J" I! y2 B2 \# S

if(nOk)

. |/ \7 ^. I2 v: t& M

' L- g+ l. j) i" f

TRACE("There is an error: %d\n",nOk);

3 t% x8 }, ?; y3 z/ v' O$ e

& p* d( j; Q/ D! Y0 w! m( l

else

* f0 V& G# Y0 E9 z8 z

8 y- {! @. f; }4 O6 G' a

TRACE("SHFileOperation finished

9 p' J/ m' \0 \, D/ e6 ~# T. T

successfully\n");

5 \: G$ b; z- A

1 z; {1 @0 W W a8 w5 a

if(FileOp.fAnyOperationsAborted)

: f6 M, R0 z% d' t. P5 ^7 v

3 v2 `) i7 g n" ^# G

TRACE("Operation was aborted!\n");

* ~! ?6 {3 D$ {& Q4 p1 q

}

8 D% j& X5 B+ j) R! M8 S+ ]

" I! L5 s4 M6 i2 L! i

2 P5 w0 f4 ?) H0 z O

三、 结束语

7 b% G4 Q% C# c

+ n K3 o; _: Q0 b/ h

---- 利用Windows API进行程序文件操作设计,它直接调用Windows操作系统中

5 _. u- U- w; B. S; u

的外壳,它的处理过程与Windows95/98/NT中的处理过程是一致的有利于我们在

/ i4 [( g5 Q9 {% Y' ?0 p# {: q

系统程序设计中保持与操作系统的一致性;同时,由于在文件处理中它是直接调

: z9 U1 U7 @' I' y3 }+ \

用WindowsAPI函数,因此不需要其它应用程序动态链接库DLL的支持。

" V8 [4 q: \3 k; s6 i+ U7 x

9 f' L$ P8 n+ B

---- 在各种开发软件中,都提供了对于文件的各种操作方式,但是它必须利用

3 z$ {7 W6 ?; V2 X L

到文件系统较为深入的知识,而且对于其操作的直观性方面也需要开发者进一步

8 }8 \/ M% q; s. M/ K. \" c% u

地设计,因此利用操作系统SHELL进行程序设计,不失是一种好的设计方法。






欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5