[原创]分享一个基于TIdFTP的上传下载单元解决方案

[原创]分享一个基于TIdFTP的上传下载单元
Delphi(Pascal) code

unit UnitIdFtpUtil;

interface

uses
  Classes, SysUtils, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdFTP, IdFTPList, IdFTPCommon;

  // FTP根目录
  const CONST_FTP_BOOT_PATH = '/';
  // FTP路径的分割符
  const CONST_FTP_PATH_SEPARATOR = '/';
  // XP操作系统路径的分割符
  const CONST_OS_PATH_SEPARATOR = '\';

  // 输出当前系统时间,格式为 yyyy-MM-dd hh:mm:ss
  function GetTime(d : TDateTime) : string;
  
  //写日志文件
  procedure WriteLog(aLogStr : String);

  // 解析远程目录,用于判断并创建目录 'a\b\c' 解析出'a', 'b', 'c'
  function ParseFullPathString(FullPathName : string) : TStringList;

  // 强制往FTP指定目录上传文件,当远程文件夹不存在时将自动创建
  function ForceUploadLocalFile(FtpClient : TIdFTP; FullPathName : string; FileName : string) : Boolean;

  // 尝试下载远程指定目录下的文件,如成功则返回临时下载文件的完整路径
  function TryDownloadRemoteFile(FtpClient : TIdFTP; FullPathName : string; FileName : string) : string;

implementation

function GetTime(d : TDateTime) : string;
begin
  Result := FormatDateTime('yyyy-MM-dd HH:mm:ss', d);
end;

procedure WriteLog(aLogStr : String);
var
   LogFile : TextFile;
   LogFileName, TmpStr: string;
begin
  TmpStr := ExtractFilePath(ParamStr(0)) + 'Temp';
  if not DirectoryExists(TmpStr) then
  begin
    CreateDir(TmpStr);
  end;

  TmpStr := ExtractFilePath(ParamStr(0)) +  'Logs\';
  if not DirectoryExists(TmpStr) then
  begin
    CreateDir(TmpStr);
  end;

  LogFileName := ExtractFilePath(ParamStr(0))
                  + 'Logs\'
                  + FormatDateTime('yyyy-mm-dd', Now) + '.txt';

  aLogStr := GetTime(Now) + ' ' + aLogStr;
  if FileExists(LogFileName) then
  begin
    AssignFile(LogFile, LogFileName);
    Append(LogFile);
    Writeln(LogFile, aLogStr);
    CloseFile(LogFile);
  end
  else
  begin
    AssignFile(LogFile, LogFileName);
    Rewrite(LogFile);
    Writeln(LogFile, aLogStr);
    CloseFile(LogFile);
  end;
end;

// 解析远程目录,用于判断并创建目录 'a\b\c' 解析出'a', 'b', 'c'
function ParseFullPathString(FullPathName : string) : TStringList;
var
  L : TStringList;
begin
  L := TStringList.Create;

  if Trim(FullPathName) <> '' then
  begin
    L.Text := StringReplace(FullPathName, CONST_FTP_PATH_SEPARATOR, #13, [rfReplaceAll]);
    L.Text := Trim(L.Text);
  end;

  Result := L;
end;

// 强制往FTP指定目录上传文件,当远程文件夹不存在时将自动创建
function ForceUploadLocalFile(FtpClient : TIdFTP; FullPathName : string;
  FileName : string) : Boolean;
var
  L, TempList : TStringList;
  I, J, PathLen : Integer;
  TempStr, CurrentRemotePath : string;
  IsPathExist : Boolean;
begin
  if not FtpClient.Connected then
  begin
    WriteLog('强制上传文件' + FileName + '失败:FTP未连接!!');
    Result := False;
    Exit;
  end
  else
  begin
    try
      L := ParseFullPathString(FullPathName);
      TempList := TStringList.Create;
      
      PathLen := L.Count - 1;

      //先从根目录开始对比
      FtpClient.ChangeDir(CONST_FTP_BOOT_PATH);
      FtpClient.List(TempList);
      TempList.Clear;

      CurrentRemotePath := ''; //当前所处远程目录,动态变化

      for I := 0 to PathLen do
      begin
        try
          TempStr := L.Strings[I];
          //WriteLog('开始尝试分析第' + IntToStr(I + 1) + '级目录:' + TempStr);

          // 找到目录标志
          IsPathExist := False;
        
          with FtpClient.DirectoryListing do
          begin
            for J := 0 to Count - 1 do
            begin
              if Items[J].ItemType = ditDirectory then
              begin
                //WriteLog('开始对比文件夹 ' + Items[J].FileName + ' VS ' + TempStr);
                if Items[J].FileName = TempStr then
                begin
                  IsPathExist := True;
                end;
              end;
            end;
          end;

          if not IsPathExist then
          begin
            FtpClient.MakeDir(TempStr);
            WriteLog('未在FTP文件夹找到目录:' + TempStr + ' 自动创建成功!');
          end;

          CurrentRemotePath := CurrentRemotePath + CONST_FTP_PATH_SEPARATOR +
            TempStr;
          FtpClient.ChangeDir(CurrentRemotePath);
          FtpClient.TransferType := ftASCII;
          FtpClient.List(TempList);
          TempList.Clear;
          
          //WriteLog('成功切入:' + TempStr);
        except
          on Err : Exception do
          begin
            WriteLog('分析对比目录:' + TempStr + '发生异常:' + Err.Message);
            Break;
            Result := False;
          end;
        end;
      end;

      //WriteLog('最后成功切入目录:' + CurrentRemotePath);
      FtpClient.TransferType := ftBinary;
      FtpClient.Put(FileName, AnsiToUtf8(ExtractFileName(FileName)));
    finally
      L.Free;
      TempList.Free;
    end;
    Result := True;
  end;
end;

// 尝试下载远程指定目录下的文件,如成功则返回临时下载文件的完整路径
function TryDownloadRemoteFile(FtpClient : TIdFTP; FullPathName : string; FileName : string) : string;
var
  L, TempList : TStringList;
  I, J, PathLen : Integer;
  TempStr, CurrentRemotePath : string;
  IsPathExist : Boolean;
begin
  if not FtpClient.Connected then
  begin
    WriteLog('下载文件' + FileName + '失败:FTP未连接!!');
    Result := '';
    Exit;
  end
  else
  begin
    try
      L := ParseFullPathString(FullPathName);
      TempList := TStringList.Create;
      
      PathLen := L.Count - 1;

      //先从根目录开始对比
      FtpClient.ChangeDir(CONST_FTP_BOOT_PATH);
      FtpClient.List(TempList);
      TempList.Clear;

      CurrentRemotePath := ''; //当前所处远程目录,动态变化

      for I := 0 to PathLen do
      begin
        try
          TempStr := L.Strings[I];
          //WriteLog('开始尝试分析第' + IntToStr(I + 1) + '级目录:' + TempStr);

          // 找到目录标志
          IsPathExist := False;
        
          with FtpClient.DirectoryListing do
          begin
            for J := 0 to Count - 1 do
            begin
              if Items[J].ItemType = ditDirectory then
              begin
                //WriteLog('开始对比文件夹 ' + Items[J].FileName + ' VS ' + TempStr);
                if Items[J].FileName = TempStr then
                begin
                  IsPathExist := True;
                end;
              end;
            end;
          end;

          if not IsPathExist then
          begin
            FtpClient.MakeDir(TempStr);
            WriteLog('未在FTP文件夹找到目录:' + TempStr + ' 自动创建成功!');
          end;

          CurrentRemotePath := CurrentRemotePath + CONST_FTP_PATH_SEPARATOR +
            TempStr;
          FtpClient.ChangeDir(CurrentRemotePath);
          FtpClient.TransferType := ftASCII;
          FtpClient.List(TempList);
          TempList.Clear;
          
          //WriteLog('成功切入:' + TempStr);
        except
          on Err : Exception do
          begin
            WriteLog('下载文件过程中在分析对比目录:' + TempStr + '时发生异常:' + Err.Message);
            Break;
            Result := '';
          end;
        end;
      end;

      WriteLog('最后成功切入目录:' + CurrentRemotePath);
      try
        FtpClient.TransferType := ftBinary;
        TempStr := ExtractFilePath(ParamStr(0)) +  'Temp/' + FullPathName;
        TempStr := StringReplace(TempStr, CONST_FTP_PATH_SEPARATOR, CONST_OS_PATH_SEPARATOR, [rfReplaceAll]);
        WriteLog(TempStr);
        ForceDirectories(TempStr);
        TempStr := TempStr + CONST_OS_PATH_SEPARATOR + FileName;
        FtpClient.Get(AnsiToUtf8(FileName), TempStr, True);
      except
        on Err : Exception do
        begin
          WriteLog('在远程目录:' + CurrentRemotePath + '下载文件:' + FileName + '时发生异常:' + Err.Message);
          Result := '';
        end;
      end;
      Result := TempStr;
    finally
      L.Free;
      TempList.Free;
    end;
  end;
end;


end.