Indy9的IdFTP完全使用

    Delphi 7自带的INDY控件,其中包含了IdFTP,可以方便的实现FTP客户端程序,参考自带的例子,其中有上传、下载、删除文件,但是不包含对文件夹的操作,得自己实现上传、下载、删除整个文件夹(带子目录和文件)。于是自己参考了网上的资料,重新整理下,使用归纳如下示例工程所示:

窗体上放置TIdFTP、TIdAntiFreeze组件,还有其他一些基本控件。当在列表框选择的是“文件夹”时,点击“下载”、“删除”就会对此文件夹进行下载或删除,若是选择的是“文件”类型,则对单个文件操作;上传分单个文件上传和上传整个目录。工程源码如下:

{*******************************************************}
{                                                       }
{       系统名称 IdFTP完全使用                          }
{       版权所有 (C) http://blog.csdn.net/akof1314      }
{       单元名称 Unit1.pas                              }
{       单元功能 在Delphi 7下实现FTP客户端              }
{                                                       }
{*******************************************************}
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdFTP, IdFTPCommon, IdFTPList, ComCtrls, IdGlobal,
  IdAntiFreezeBase, IdAntiFreeze, FileCtrl;

type
  TForm1 = class(TForm)
    idftp_Client: TIdFTP;
    edt_CurrentDirectory: TEdit;
    lst_ServerList: TListBox;
    edt_ServerAddress: TEdit;
    edt_UserName: TEdit;
    edt_UserPassword: TEdit;
    lbl1: TLabel;
    lbl2: TLabel;
    lbl3: TLabel;
    lbl4: TLabel;
    btn_Connect: TButton;
    btn_EnterDirectory: TButton;
    btn_Back: TButton;
    btn_Download: TButton;
    btn_Upload: TButton;
    btn_Delete: TButton;
    btn_MKDirectory: TButton;
    btn_Abort: TButton;
    mmo_Log: TMemo;
    pb_ShowWorking: TProgressBar;
    dlgSave_File: TSaveDialog;
    lbl_ShowWorking: TLabel;
    idntfrz1: TIdAntiFreeze;
    dlgOpen_File: TOpenDialog;
    btn_UploadDirectory: TButton;
    procedure btn_ConnectClick(Sender: TObject);
    procedure btn_EnterDirectoryClick(Sender: TObject);
    procedure btn_BackClick(Sender: TObject);
    procedure lst_ServerListDblClick(Sender: TObject);
    procedure btn_DownloadClick(Sender: TObject);
    procedure idftp_ClientWork(Sender: TObject; AWorkMode: TWorkMode;
      const AWorkCount: Integer);
    procedure idftp_ClientWorkBegin(Sender: TObject; AWorkMode: TWorkMode;
      const AWorkCountMax: Integer);
    procedure idftp_ClientWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
    procedure FormCreate(Sender: TObject);
    procedure btn_AbortClick(Sender: TObject);
    procedure btn_UploadClick(Sender: TObject);
    procedure btn_DeleteClick(Sender: TObject);
    procedure btn_MKDirectoryClick(Sender: TObject);
    procedure btn_UploadDirectoryClick(Sender: TObject);
  private
    FTransferrignData: Boolean;    //是否在传输数据
    FBytesToTransfer: LongWord;    //传输的字节大小
    FAbortTransfer: Boolean;       //取消数据传输
    STime : TDateTime;             //时间
    FAverageSpeed : Double;        //平均速度
    procedure ChageDir(DirName: String);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
{-------------------------------------------------------------------------------
 Description: 窗体创建函数
-------------------------------------------------------------------------------}
procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.DoubleBuffered := True;     //开启双缓冲,使得lbl_ShowWorking描述不闪烁
  idntfrz1.IdleTimeOut := 50;
  idntfrz1.OnlyWhenIdle := False;
end;
{-------------------------------------------------------------------------------
 Description: 连接、断开连接
-------------------------------------------------------------------------------}
procedure TForm1.btn_ConnectClick(Sender: TObject);
begin
  btn_Connect.Enabled := False;
  if idftp_Client.Connected then
  begin
    //已连接
    try
      if FTransferrignData then      //是否数据在传输
        idftp_Client.Abort;
      idftp_Client.Quit;
    finally
      btn_Connect.Caption := '连接';
      edt_CurrentDirectory.Text := '/';
      lst_ServerList.Items.Clear;
      btn_Connect.Enabled := True;
      mmo_Log.Lines.Add(DateTimeToStr(Now) + '断开服务器');
    end;   
  end
  else
  begin
    //未连接
    with idftp_Client do
    try
      Passive := True; //被动模式
      Username := Trim(edt_UserName.Text);
      Password := Trim(edt_UserPassword.Text);
      Host := Trim(edt_ServerAddress.Text);
      Connect();
      Self.ChageDir(edt_CurrentDirectory.Text);
    finally
      btn_Connect.Enabled := True;
      if Connected then
        btn_Connect.Caption := '断开连接';
        mmo_Log.Lines.Add(DateTimeToStr(Now) + '连接服务器');
    end;
  end;
end;
{-------------------------------------------------------------------------------
 Description: 改变目录
-------------------------------------------------------------------------------}
procedure TForm1.ChageDir(DirName: String);
var
  LS: TStringList;
  i: Integer;
begin
  LS := TStringList.Create;
  try
    idftp_Client.ChangeDir(AnsiToUtf8(DirName));
    idftp_Client.TransferType := ftASCII;
    edt_CurrentDirectory.Text := Utf8ToAnsi(idftp_Client.RetrieveCurrentDir);
    idftp_Client.List(LS);
    LS.Clear;
    with idftp_Client.DirectoryListing do
    begin
      for i := 0 to Count - 1 do
      begin
        if Items[i].ItemType = ditDirectory then
          LS.Add(Format('%-22s%15s%-10s%s',[Utf8ToAnsi(Items[i].FileName),IntToStr(Items[i].Size),'  文件夹',DateTimeToStr(Items[i].ModifiedDate)]))
        else
          LS.Add(Format('%-22s%15s%-10s%s',[Utf8ToAnsi(Items[i].FileName),IntToStr(Items[i].Size),'  文件',DateTimeToStr(Items[i].ModifiedDate)]));
      end;
    end;
    lst_ServerList.Items.Clear;
    lst_ServerList.Items.Assign(LS);
  finally
    LS.Free;
  end;   
end;
{-------------------------------------------------------------------------------
 Description: 进入目录按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_EnterDirectoryClick(Sender: TObject);
begin
  Self.ChageDir(edt_CurrentDirectory.Text);
end;
{-------------------------------------------------------------------------------
 Description: 后退按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_BackClick(Sender: TObject);
begin
  Self.ChageDir('..');
end;
{-------------------------------------------------------------------------------
 Description: 双击文件夹名称,进入该目录
-------------------------------------------------------------------------------}
procedure TForm1.lst_ServerListDblClick(Sender: TObject);
begin
  if not idftp_Client.Connected then
    Exit;
  if idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].ItemType = ditDirectory then
    Self.ChageDir(Utf8ToAnsi(idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].FileName));
end;
{-------------------------------------------------------------------------------
 Description: 下载按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_DownloadClick(Sender: TObject);
 procedure DownloadDirectory(var idFTP: TIdFtp;LocalDir, RemoteDir: string);
 var
   i,DirCount: Integer;
   strName: string;
 begin
   if not DirectoryExists(LocalDir + RemoteDir) then
   begin
     ForceDirectories(LocalDir + RemoteDir);  //创建一个全路径的文件夹
     mmo_Log.Lines.Add('建立目录:' + LocalDir + RemoteDir);
   end;
   idFTP.ChangeDir(AnsiToUtf8(RemoteDir));
   idFTP.TransferType := ftASCII;
   idFTP.List(nil);
   DirCount := idFTP.DirectoryListing.Count;
   for i := 0 to DirCount - 1 do
   begin
     strName := Utf8ToAnsi(idFTP.DirectoryListing.Items[i].FileName);
     mmo_Log.Lines.Add('解析文件:' + strName);
     if idFTP.DirectoryListing.Items[i].ItemType = ditDirectory then
       if (strName = '.') or (strName = '..') then
         Continue
       else
       begin
         DownloadDirectory(idFTP,LocalDir + RemoteDir + '/', strName);
         idFTP.ChangeDir('..');
         idFTP.List(nil);
       end
     else
     begin
       if (ExtractFileExt(strName) = '.txt') or (ExtractFileExt(strName) = '.html') or (ExtractFileExt(strName) = '.htm') then
         idFTP.TransferType := ftASCII    //文本模式
       else
         idFTP.TransferType := ftBinary;   //二进制模式
       FBytesToTransfer := idFTP.Size(AnsiToUtf8(strName));        ;
       idFTP.Get(AnsiToUtf8(strName), LocalDir + RemoteDir + '/' + strName, True);
       mmo_Log.Lines.Add('下载文件:' + strName);
     end;
     Application.ProcessMessages;
   end;
 end;
var
  strName: string;
  strDirectory: string;
begin
  if not idftp_Client.Connected then
    Exit;
  btn_Download.Enabled := False;
  strName := idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].FileName;
  if idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].ItemType = ditDirectory then
  begin
    if SelectDirectory('选择目录保存路径','',strDirectory) then
    begin
      DownloadDirectory(idftp_Client,strDirectory + '/',Utf8ToAnsi(strName));
      idftp_Client.ChangeDir('..');
      idftp_Client.List(nil);
    end;
  end
  else
  begin
    //下载单个文件
    dlgSave_File.FileName := Utf8ToAnsi(strName);
    if dlgSave_File.Execute then
    begin
      idftp_Client.TransferType := ftBinary;
      FBytesToTransfer := idftp_Client.Size(strName);
      if FileExists(dlgSave_File.FileName) then
      begin
        case MessageDlg('文件已经存在,是否要继续下载?',  mtConfirmation, mbYesNoCancel, 0) of
          mrCancel:  //退出操作
            begin
              Exit;
            end;
          mrYes:    //断点继续下载文件
            begin
              FBytesToTransfer := FBytesToTransfer - FileSizeByName(strName);
              idftp_Client.Get(strName,dlgSave_File.FileName,False,True);
            end;
          mrNo:     //从头开始下载文件
            begin
              idftp_Client.Get(strName,dlgSave_File.FileName,True);
            end;
        end;
      end
      else
        idftp_Client.Get(strName, dlgSave_File.FileName, False);
    end;  
  end;
  btn_Download.Enabled := True;
end;
{-------------------------------------------------------------------------------
 Description: 读写操作的工作事件
-------------------------------------------------------------------------------}
procedure TForm1.idftp_ClientWork(Sender: TObject; AWorkMode: TWorkMode;
  const AWorkCount: Integer);
Var
  S: String;
  TotalTime: TDateTime;
  H, M, Sec, MS: Word;
  DLTime: Double;
begin
  TotalTime :=  Now - STime;      //已花费的时间
  DecodeTime(TotalTime, H, M, Sec, MS);  //解码时间
  Sec := Sec + M * 60 + H * 3600;  //转换成以秒计算
  DLTime := Sec + MS / 1000;      //精确到毫秒
  if DLTime > 0 then
    FAverageSpeed := (AWorkCount / 1024) / DLTime;   //求平均速度
  if FAverageSpeed > 0 then
  begin
    Sec := Trunc(((pb_ShowWorking.Max - AWorkCount) / 1024) / FAverageSpeed);
    S := Format('%2d:%2d:%2d', [Sec div 3600, (Sec div 60) mod 60, Sec mod 60]);
    S := '剩余时间 ' + S;
  end
  else
    S := '';
  S := FormatFloat('0.00 KB/s', FAverageSpeed) + '; ' + S;
  case AWorkMode of
    wmRead: lbl_ShowWorking.Caption := '下载速度 ' + S;
    wmWrite: lbl_ShowWorking.Caption := '上传速度 ' + S;
  end;
  if FAbortTransfer then   //取消数据传输
    idftp_Client.Abort;
  pb_ShowWorking.Position := AWorkCount;
  FAbortTransfer := false;
end;
{-------------------------------------------------------------------------------
 Description: 开始读写操作的事件
-------------------------------------------------------------------------------}
procedure TForm1.idftp_ClientWorkBegin(Sender: TObject;
  AWorkMode: TWorkMode; const AWorkCountMax: Integer);
begin
  FTransferrignData := True;
  btn_Abort.Enabled := True;
  FAbortTransfer := False;
  STime := Now;
  if AWorkCountMax > 0 then
    pb_ShowWorking.Max := AWorkCountMax
  else
    pb_ShowWorking.Max := FBytesToTransfer;
  FAverageSpeed := 0;
end;
{-------------------------------------------------------------------------------
 Description: 读写操作完成之后的事件
-------------------------------------------------------------------------------}
procedure TForm1.idftp_ClientWorkEnd(Sender: TObject;
  AWorkMode: TWorkMode);
begin
  btn_Abort.Enabled := False;
  FTransferrignData := False;
  FBytesToTransfer := 0;
  pb_ShowWorking.Position := 0;
  FAverageSpeed := 0;
  lbl_ShowWorking.Caption := '传输完成';
end;
{-------------------------------------------------------------------------------
 Description: 取消按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_AbortClick(Sender: TObject);
begin
  FAbortTransfer := True;
end;
{-------------------------------------------------------------------------------
 Description: 上传按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_UploadClick(Sender: TObject);
begin
  if idftp_Client.Connected then
  begin
    if dlgOpen_File.Execute then
    begin
      idftp_Client.TransferType := ftBinary;
      idftp_Client.Put(dlgOpen_File.FileName, AnsiToUtf8(ExtractFileName(dlgOpen_File.FileName)));
      ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));
    end;
  end;  
end;
{-------------------------------------------------------------------------------
 Description: 删除按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_DeleteClick(Sender: TObject);
  procedure DeleteDirectory(var idFTP: TIdFtp; RemoteDir: string);
  var
    i,DirCount: Integer;
    strName: string;
  begin
    idFTP.List(nil);
    DirCount := idFTP.DirectoryListing.Count;
    if DirCount = 2 then
    begin
      idFTP.ChangeDir('..');
      idFTP.RemoveDir(RemoteDir);
      idFTP.List(nil);
      Application.ProcessMessages;
      mmo_Log.Lines.Add('删除文件夹:' + Utf8ToAnsi(RemoteDir));
      Exit;
    end;
    for i := 0 to 2 do
    begin
      strName := idFTP.DirectoryListing.Items[i].FileName;
      if idFTP.DirectoryListing.Items[i].ItemType = ditDirectory then
      begin
        if (strName = '.') or (strName = '..') then
         Continue;
        idFTP.ChangeDir(strName);
        DeleteDirectory(idFTP,strName);
        DeleteDirectory(idFTP,RemoteDir);
      end
      else
      begin
        idFTP.Delete(strName);
        Application.ProcessMessages;
        mmo_Log.Lines.Add('删除文件:' + Utf8ToAnsi(strName));
        DeleteDirectory(idFTP,RemoteDir);
      end;  
    end;
  end;
Var
  strName: String;
begin
  if not idftp_Client.Connected then
    exit;
  strName := idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].FileName;
  if idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].ItemType = ditDirectory then
    try
      idftp_Client.ChangeDir(strName);
      DeleteDirectory(idftp_Client,strName);
      ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));
    finally
    end
  else       //删除单个文件
    try
      idftp_Client.Delete(strName);
      ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));
    finally
    end;
end;
{-------------------------------------------------------------------------------
 Description: 新建目录按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_MKDirectoryClick(Sender: TObject);
var
  S: string;
begin
  if InputQuery('新建目录','文件夹名称',S) and (Trim(S) <> '') then
  begin
    idftp_Client.MakeDir(AnsiToUtf8(S));
    Self.ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));
  end;
end;
{-------------------------------------------------------------------------------
 Description: 上传目录按钮
-------------------------------------------------------------------------------}
procedure TForm1.btn_UploadDirectoryClick(Sender: TObject);
  function DoUploadDir(idftp:TIdFTP;sDirName:String;sToDirName:String):Boolean;
  var
    hFindFile:Cardinal;
    tfile:String;
    sCurDir:String[255];
    FindFileData:WIN32_FIND_DATA;
  begin
    //先保存当前目录
    sCurDir:=GetCurrentDir;
    ChDir(sDirName);
    idFTP.ChangeDir(AnsiToUtf8(sToDirName));
    hFindFile:=FindFirstFile( '*.* ',FindFileData);
    Application.ProcessMessages;
    if hFindFile<>INVALID_HANDLE_VALUE then
    begin
      repeat
        tfile:=FindFileData.cFileName;
        if (tfile= '.') or (tfile= '..') then
              Continue;
        if FindFileData.dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY then
        begin
          try
            IdFTP.MakeDir(AnsiToUtf8(tfile));
            mmo_Log.Lines.Add('新建文件夹:' + tfile);
          except
          end;
          DoUploadDir(idftp,sDirName+ '/'+tfile,tfile);
          idftp.ChangeDir('..');
          Application.ProcessMessages;
        end
        else
        begin
          IdFTP.Put(tfile, AnsiToUtf8(tfile));
          mmo_Log.Lines.Add('上传文件:' + tfile);
          Application.ProcessMessages;
        end;
      until   FindNextFile(hFindFile,FindFileData)=false;
    end
    else
    begin
      ChDir(sCurDir);
      result:=false;
      exit;
    end;
    //回到原来的目录下
    ChDir(sCurDir);
    result:=true;
  end;
var
  strPath,strToPath,temp: string;
begin
  if idftp_Client.Connected then
  begin
    if SelectDirectory('选择上传目录','',strPath) then
    begin
      temp := Utf8ToAnsi(idftp_Client.RetrieveCurrentDir);
      strToPath := temp;
      if Length(strToPath) = 1 then
        strToPath := strToPath +  ExtractFileName(strPath)
      else
        strToPath := strToPath + '/' +  ExtractFileName(strPath);
      try
        idftp_Client.MakeDir(AnsiToUtf8(ExtractFileName(strPath)));
      except
      end;
      DoUploadDir(idftp_Client,strPath,strToPath);
      Self.ChageDir(temp);
    end;
  end;  
end;

end.

运行工程如下图所示:

示例源码下载:https://download.csdn.net/download/akof1314/3236325

你可能感兴趣的:(5.2,Delphi编程,integer,string,delphi,download,file,forms)