本文共 11784 字,大约阅读时间需要 39 分钟。
Delphi 7自带的INDY控件提供了强大的FTP客户端功能,其中IdFTP组件是实现FTP连接的核心。通过IdFTP,可以方便地实现文件上传、下载和删除等基本操作。然而,原始的INDY控件库中并没有直接支持文件夹操作,这使得开发者需要额外实现文件夹的创建、删除和遍历功能。以下将详细介绍如何实现文件夹操作,并基于实际开发经验,提供一个完整的解决方案。
在Delphi 7中,首先需要配置项目单位,引入必要的组件。开发过程中需要使用到以下组件:
整个应用程序主要包含以下功能模块:
以下是实现各功能模块的主要代码片段:
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; 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; 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;
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; 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; procedure TForm1.btn_AbortClick(Sender: TObject);begin FAbortTransfer := True;end;
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; 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; 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; 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; 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; 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;
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;
procedure TForm1.btn_AbortClick(Sender: TObject);begin FAbortTransfer := True;end;
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/