TSHFileOpStruct

把一个文件从一个目录拷贝到另一个目录

 

标  题: Re: 把一个文件从一个目录拷贝到另一个目录

发信站: BBS 水木清华站 (Tue Mar 27 14:38:58 2001)

 

我来贴个shellAPI解决这类问题的通用办法吧

 

3.1  整个目录的复制、移动、删除

实例说明

Delphi的用户都知道,删除目录可用RemoveDir函数,但此函数只能删除空目录,如果目

录中有子目录或其它文件,那么此函数就会失败;而删除文件可用DeleteFile函数,但

此函数只能删除单个文件;而且,Delphi并没有提供与空目录或单个文件的复制或移动

相关的函数,更不用说要对整个非空目录以及多个文件的复制、移动和删除了。但通过

本例的分析,读者就能够自由地对任何目录(空目录及非空目录)或多(包括单个)个

文件进行复制、移动、删除了;而且,在上述操作过程中,我们还可以加上进度条,使

整个操作就和在Windows的资源管理器中所作的复制、移动和删除操作完全一样。程序执

行结果如图3.1.1、图3.1.2和图3.1.3所示。

图3.1.1  程序运行主界面

图3.1.2  复制文件过程中的进程条

图3.1.3  复制完毕的提示对话框

设计思想

读者可能想用循环来实现上述功能,但这没有必要,因为有现成的API函数SHFileOpera

tion可以实现上述功能,只需作相应的设置即可。MSDN中此函数的声明为:

WINSHELLAPI int WINAPI SHFileOperation(

    LPSHFILEOPSTRUCT lpFileOp //指向SHFILEOPSTRUCT结构体的指针

   );

函数执行成功返回0,否则如有错误返回值非0。

SHFILEOPSTRUCT结构体的定义如下:

typedef struct _SHFILEOPSTRUCT { // shfos

    HWND         hwnd; //显示状态信息窗口的句柄,一般设为主窗体的句柄

    UINT         wFunc; //要执行的操作

    LPCSTR       pFrom; //源文件或目录

    LPCSTR       pTo; //目标文件或目录

    FILEOP_FLAGS fFlags; //控制文件操作的标志

    BOOL         fAnyOperationsAborted; //操作是否放弃

    LPVOID       hNameMappings; //文件名映射对象的句柄,很少用

    LPCSTR       lpszProgressTitle; //进度条标题,仅在fFlags标志中指定了//FO

F_SIMPLEPROGRESS时有效

} SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT;

Delphi用记录TSHFileOpStruct对此结构做了两种封装:ANSI字符和宽字符版本。读者可

从ShellAPI单元的第265行看到如下代码:

  _SHFILEOPSTRUCTA = packed record  //ANSI版本

    Wnd: HWND;

    wFunc: UINT;

    pFrom: PAnsiChar;

    pTo: PAnsiChar;

    fFlags: FILEOP_FLAGS;

    fAnyOperationsAborted: BOOL;

    hNameMappings: Pointer;

    lpszProgressTitle: PAnsiChar; { only used if FOF_SIMPLEPROGRESS }

  end;

  {$EXTERNALSYM _SHFILEOPSTRUCTW}

  _SHFILEOPSTRUCTW = packed record //宽字符版本

    Wnd: HWND;

    wFunc: UINT;

    pFrom: PWideChar;

    pTo: PWideChar;

    fFlags: FILEOP_FLAGS;

    fAnyOperationsAborted: BOOL;

    hNameMappings: Pointer;

    lpszProgressTitle: PWideChar; { only used if FOF_SIMPLEPROGRESS }

  end;

  {$EXTERNALSYM _SHFILEOPSTRUCT}

  _SHFILEOPSTRUCT = _SHFILEOPSTRUCTA;

  TSHFileOpStructA = _SHFILEOPSTRUCTA;

  TSHFileOpStructW = _SHFILEOPSTRUCTW;

  TSHFileOpStruct = TSHFileOpStructA;

  //默认情况下TSHFileOpStruct为ANSI版本

  {$EXTERNALSYM SHFILEOPSTRUCTA}

  SHFILEOPSTRUCTA = _SHFILEOPSTRUCTA;

  {$EXTERNALSYM SHFILEOPSTRUCTW}

  SHFILEOPSTRUCTW = _SHFILEOPSTRUCTW;

  {$EXTERNALSYM SHFILEOPSTRUCT}

  SHFILEOPSTRUCT = SHFILEOPSTRUCTA;

 //默认情况下SHFILEOPSTRUCT为ANSI版本

在ShellAPI单元的第200行对wFunc参数的取值定义了4种操作:

  {$EXTERNALSYM FO_MOVE}

  FO_MOVE           = $0001; //移动操作,从pFrom到pTo

  {$EXTERNALSYM FO_COPY}

  FO_COPY           = $0002; //复制操作,从pFrom到pTo

  {$EXTERNALSYM FO_DELETE}

  FO_DELETE         = $0003; //删除操作,删除pFrom中指定的目录或文件(忽略//

pTo参数)

  {$EXTERNALSYM FO_RENAME}

  FO_RENAME         = $0004; //重命名操作,重命名pFrom中指定的目录或文件。

在ShellAPI单元的第210行对fFlags参数定义了如下可能取值:

  {$EXTERNALSYM FOF_MULTIDESTFILES}

  FOF_MULTIDESTFILES         = $0001; //表明pTo 参数是多个文件而不是一个//目

  {$EXTERNALSYM FOF_CONFIRMMOUSE}

  FOF_CONFIRMMOUSE           = $0002; //目前没有实现

  {$EXTERNALSYM FOF_SILENT}

  FOF_SILENT                 = $0004;  //不创建进度条/报告

  {$EXTERNALSYM FOF_RENAMEONCOLLISION}

  FOF_RENAMEONCOLLISION      = $0008; //当目标文件已存在时,将源文件改

//名再复制或移动

  {$EXTERNALSYM FOF_NOCONFIRMATION}

  FOF_NOCONFIRMATION         = $0010;  //操作过程中不显示确认信息,相当//于用

户选择了“yes to all”

  {$EXTERNALSYM FOF_WANTMAPPINGHANDLE}

  FOF_WANTMAPPINGHANDLE = $0020;  //填充hNameMappings成员

  {$EXTERNALSYM FOF_ALLOWUNDO}

  FOF_ALLOWUNDO              = $0040;  //允许撤销操作

  {$EXTERNALSYM FOF_FILESONLY}

  FOF_FILESONLY              = $0080;  //只操作文件

  {$EXTERNALSYM FOF_SIMPLEPROGRESS}

  FOF_SIMPLEPROGRESS         = $0100;  //显示进度条对话框但不显示文件名

  {$EXTERNALSYM FOF_NOCONFIRMMKDIR}

  FOF_NOCONFIRMMKDIR         = $0200;  //新建目录时不提示确认

  {$EXTERNALSYM FOF_NOERRORUI}

  FOF_NOERRORUI              = $0400;  //如果操作出错,不显示用户借口

设计步骤

新建一应用程序,按照图3.1.1所示加入2个TStaticText组件、2个TEdit组件和5个TBut

ton组件;TstaticText和TButton组件的Caption属性设置为如图所示,TEdit组件的Tex

t属性清空。

在uses中加入FileCtrl,shellapi两单元。SelectDirectory函数用到FileCtrl单元,而

SHFileOperation函数及TSHFileOpStruct记录用到shellapi单元。

代码分析

在第一个“…”按钮的OnClick事件中加入如下代码,用于选择操作的源目录:

procedure TForm1.Button4Click(Sender: TObject);

var

  Dir: string;

begin

  Dir := 'D:';

  if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then

//函数执行成功

// sdAllowCreate:允许创建目录

// sdPerformCreate:执行创建目录

// sdPrompt:显示提示信息

    edit1.text:= Dir;

end;

在第二个“…”按钮的OnClick事件中加入如下代码,用于选择操作的目标目录:

procedure TForm1.Button5Click(Sender: TObject);

var

  Dir: string;

begin

  Dir := 'D:';

  if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then

 //解释同上

    edit2.text:= Dir;

end;

在“复制”按钮的OnClick事件中加入如下代码,用于执行复制操作:

procedure TForm1.Button1Click(Sender: TObject);

var

  OpStruc:TSHFileOpStruct;

  FromBuf,ToBuf:Array[0..128] of Char;

begin

  FillChar(FromBuf,Sizeof(FromBuf),0);

  FillChar(ToBuf,Sizeof(ToBuf),0);

  //用0初始化FromBuf和ToBuf数组

  StrPCopy(FromBuf,Pchar(Edit1.Text));

  StrPCopy(ToBuf,Pchar(Edit2.Text));

  //分别在 FromBuf和ToBuf数组中填入操作的源目录及目标目录

  //开始填充OpStruc记录

  with OpStruc do

  begin

    Wnd:=Handle;

    wFunc:=FO_COPY;

  //复制操作

    pFrom:=@FromBuf;

    pTo:=@ToBuf;

    fFlags:=FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION;

    fAnyOperationsAborted:=False;

    hNameMappings:=nil;

    lpszProgressTitle:=nil;

  end;

  if SHFileOperation(OpStruc)=0 then

 //函数执行成功

  MessageBox(Handle,'复制完毕。','复制信息',MB_OK+MB_ICONINFORMATION);

end;

在“移动”按钮的OnClick事件中加入如下代码,用于执行移动操作:

procedure TForm1.Button2Click(Sender: TObject);

var

  OpStruc:TSHFileOpStruct;

  FromBuf,ToBuf:Array[0..128] of Char;

begin

  FillChar(FromBuf,Sizeof(FromBuf),0);

  FillChar(ToBuf,Sizeof(ToBuf),0);

  StrPCopy(FromBuf,Pchar(Edit1.Text));

  StrPCopy(ToBuf,Pchar(Edit2.Text));

  //开始填充OpStruc记录

  with OpStruc do

  begin

    Wnd:=Handle;

    wFunc:=FO_MOVE;

   //移动操作

    pFrom:=@FromBuf;

    pTo:=@ToBuf;

    fFlags:=FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION;

    fAnyOperationsAborted:=False;

    hNameMappings:=nil;

    lpszProgressTitle:='正在文件';

  end;

  if SHFileOperation(OpStruc)=0 then

  //执行成功

  MessageBox(Handle,'移动完毕。','移动信息',MB_OK+MB_ICONINFORMATION);

end;

在“删除”按钮的OnClick事件中加入如下代码,用于执行删除操作:

procedure TForm1.Button3Click(Sender: TObject);

var

  OpStruc:TSHFileOpStruct;

  FromBuf:Array[0..128] of Char;

begin

  FillChar(FromBuf,Sizeof(FromBuf),0);

  StrPCopy(FromBuf,Pchar(Edit1.Text));

  //开始填充OpStruc记录

  with OpStruc do

  begin

    Wnd:=Handle;

    wFunc:=FO_DELETE;

    pFrom:=@FromBuf;

    pTo:=nil;

    fFlags:=FOF_NOCONFIRMATION;

    lpszProgressTitle:='正在删除';

  end;

  if SHFileOperation(OpStruc)=0 then

  //执行成功

  MessageBox(Handle,'删除完毕。','删除信息',MB_OK+MB_ICONINFORMATION);

end;

总结

注意:删除时(wFunc参数设为FO_DELETE)如果想将文件或目录放到回收站(fFlags参

数设置为FOF_ALLOWUNDO)则应该给出文件的绝对路径名,否则可能无法恢复。对于多个

文件的操作,文件名之间要以#0)字符分隔,整个字符串以两个# 0 结束。

 

posted @ 2011-12-09 16:53  唯一的事  阅读(1868)  评论(0编辑  收藏  举报