博客
关于我
Indy9的IdFTP完全使用
阅读量:159 次
发布时间:2019-02-27

本文共 11784 字,大约阅读时间需要 39 分钟。

Delphi 7自带的INDY控件提供了强大的FTP客户端功能,其中IdFTP组件是实现FTP连接的核心。通过IdFTP,可以方便地实现文件上传、下载和删除等基本操作。然而,原始的INDY控件库中并没有直接支持文件夹操作,这使得开发者需要额外实现文件夹的创建、删除和遍历功能。以下将详细介绍如何实现文件夹操作,并基于实际开发经验,提供一个完整的解决方案。

1. 组件配置与初始化

在Delphi 7中,首先需要配置项目单位,引入必要的组件。开发过程中需要使用到以下组件:

  • TIdFTP:用于实现FTP客户端连接
  • TIdAntiFreeze:优化FTP传输过程中的性能
  • TProgressBar:显示传输进度
  • TListBox:用于显示文件和文件夹列表

2. 功能模块设计

整个应用程序主要包含以下功能模块:

  • 连接FTP服务器:配置服务器信息并建立连接
  • 目录切换:支持进入文件夹和返回上级目录
  • 文件上传:支持单文件和目录上传
  • 文件下载:支持单文件和目录下载
  • 文件删除:支持单文件和目录删除
  • 文件夹创建:支持在指定目录下创建新的文件夹
  • 传输状态显示:实时显示传输进度和速度信息
  • 传输取消:支持中断当前传输

3. 代码实现

以下是实现各功能模块的主要代码片段:

3.1 连接FTP服务器

procedure TForm1.btn_ConnectClick(Sender: TObject);begin  btn_Connect.Enabled := False;  if idftp_Client.Connected then  begin    idftp_Client.Abort;    idftp_Client.Quit;    btn_Connect.Caption := '连接';    Self.ChageDir('/'); // 切换到根目录    mmo_Log.Lines.Add('断开服务器');  else  begin    idftp_Client.Pasive := True;    idftp_Client.Username := edt_UserName.Text;    idftp_Client.Password := edt_UserPassword.Text;    idftp_Client.Host := edt_ServerAddress.Text;    idftp_Client.Connect();    Self.ChageDir(edt_CurrentDirectory.Text);    mmo_Log.Lines.Add('连接服务器');  end;  btn_Connect.Enabled := True;end;

3.2 切换目录

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;

3.3 文件上传

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)));      Self.ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));    end;  end;end;

3.4 文件下载

procedure TForm1.btn_DownloadClick(Sender: TObject);var  strName: String;begin  if idftp_Client.Connected then  begin    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 AbortTransfer; 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;  end;end;

4. 传输状态显示

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;

5. 传输取消

procedure TForm1.btn_AbortClick(Sender: TObject);begin  FAbortTransfer := True;end;

6. 文件删除

procedure TForm1.btn_DeleteClick(Sender: TObject);var  strName: String;begin  if idftp_Client.Connected then  begin    strName := idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].FileName;    if idftp_Client.DirectoryListing.Items[lst_ServerList.ItemIndex].ItemType = ditDirectory then    begin      try        idftp_Client.ChangeDir(strName);        DeleteDirectory(idftp_Client, strName);        Self.ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));      finally        idftp_Client.ChangeDir('..');        idftp_Client.List(nil);      end;    end    else    begin      try        idftp_Client.Delete(strName);        Self.ChageDir(Utf8ToAnsi(idftp_Client.RetrieveCurrentDir));      finally        idftp_Client.List(nil);      end;    end;  end;end;

7. 文件夹创建

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;

8. 上传整个目录

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(temp) = 1 then        strToPath := temp + ExtractFileName(strPath)      else        strToPath := temp + '/' + ExtractFileName(strPath);      try        idftp_Client.MakeDir(AnsiToUtf8(ExtractFileName(strPath)));      except      end;      DoUploadDir(idftp_Client, strPath, strToPath);      Self.ChageDir(temp);    end;  end;end;

9. 下载整个目录

procedure TForm1.btn_DownloadDirectoryClick(Sender: TObject);var  strName: String;begin  if idftp_Client.Connected then  begin    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  end;end;

10. 文件夹删除

procedure TForm1.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, RemoteDir);      DeleteDirectory(idFTP, RemoteDir);    end    else    begin      idFTP.Delete(strName);      Application.ProcessMessages;      DeleteDirectory(idFTP, RemoteDir);    end;  end;end;

11. 传输状态显示

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;

12. 传输完成

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;

13. 传输取消

procedure TForm1.btn_AbortClick(Sender: TObject);begin  FAbortTransfer := True;end;

14. 上传整个目录

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(temp) = 1 then        strToPath := temp + ExtractFileName(strPath)      else        strToPath := temp + '/' + ExtractFileName(strPath);      try        idftp_Client.MakeDir(AnsiToUtf8(ExtractFileName(strPath)));      except      end;      DoUploadDir(idftp_Client, strPath, strToPath);      Self.ChageDir(temp);    end;  end;end;

通过以上代码片段,可以实现一个功能齐全的FTP客户端程序,支持文件和文件夹的上传、下载、删除等操作。整个程序采用了模块化设计,代码结构清晰,易于维护和扩展。

总结

通过以上实现,可以看到Delphi 7中的INDY控件如何高效地支持FTP客户端功能开发。通过合理配置组件、设计模块化代码,并结合实际需求逐一实现功能,可以打造一个功能完善的FTP客户端工具。

转载地址:http://haid.baihongyu.com/

你可能感兴趣的文章
non linear processor
查看>>
Non-final field ‘code‘ in enum StateEnum‘
查看>>
none 和 host 网络的适用场景 - 每天5分钟玩转 Docker 容器技术(31)
查看>>
None还可以是函数定义可选参数的一个默认值,设置成默认值时实参在调用该函数时可以不输入与None绑定的元素...
查看>>
NoNodeAvailableException None of the configured nodes are available异常
查看>>
Vue.js 学习总结(16)—— 为什么 :deep、/deep/、>>> 样式能穿透到子组件
查看>>
nopcommerce商城系统--文档整理
查看>>
NOPI读取Excel
查看>>
NoSQL&MongoDB
查看>>
NoSQL介绍
查看>>
NoSQL数据库概述
查看>>
Notadd —— 基于 nest.js 的微服务开发框架
查看>>
NOTE:rfc5766-turn-server
查看>>
Notepad ++ 安装与配置教程(非常详细)从零基础入门到精通,看完这一篇就够了
查看>>
Notepad++在线和离线安装JSON格式化插件
查看>>
notepad++最详情汇总
查看>>
notepad++正则表达式替换字符串详解
查看>>
notepad如何自动对齐_notepad++怎么自动排版
查看>>
Notes on Paul Irish's "Things I learned from the jQuery source" casts
查看>>
Notification 使用详解(很全
查看>>