用INDY9开发FTP客户端_05

用INDY9开发FTP客户端_05

-- 实现FTP断点续传和下载限速的例程

Roger Yang

1.  TIdFTP的GET()方法实现断点续传的例程:
    procedure TMainForm.DirectoryListBoxDblClick(Sender: TObject);
    Var
        Name{, Line}: String;
    begin
      // 如果未与FTP服务器连接,则退出
      if not IdFTP1.Connected then exit;
      //Line := DirectoryListBox.Items[DirectoryListBox.ItemIndex];
      // 获得文件名
      Name := IdFTP1.DirectoryListing.Items[DirectoryListBox.ItemIndex].FileName;
      // 判断用户所选是文件还是目录
      if IdFTP1.DirectoryListing.Items[DirectoryListBox.ItemIndex].ItemType = ditDirectory then begin
        // Change directory
        // 如果选择的是目录,则进入这个目录
        SetFunctionButtons(false);
        ChageDir(Name);
        SetFunctionButtons(true);
      end
      else begin
        try
          // 服务器上的文件名作为保存对话框的默认文件名.
          SaveDialog1.FileName := Name;
         
          // 判断用户在保存对话框中是否单机了确认键.
          if SaveDialog1.Execute then begin
            SetFunctionButtons(false);
           
            // 以二进制方式进行传输
            IdFTP1.TransferType := ftBinary;
           
            // 默认需要传输的字节数就是文件的大小
            BytesToTransfer := IdFTP1.Size(Name);
           
            // 判断文件是否存在
            if FileExists(Name) then begin
              // 如果文件已存在,就要询问用户是断点续传,还是覆盖.
              case MessageDlg('File aready exists. Do you want to resume the download operation?',
                mtConfirmation, mbYesNoCancel, 0) of
                mrYes: begin
                  // 如果续传,那么传输的字节数就是文件总大小减去已传输的字节.
                  BytesToTransfer := BytesToTransfer - FileSizeByName(Name);
                  IdFTP1.Get(Name, SaveDialog1.FileName, false, true);
                end;
                mrNo: begin
                  IdFTP1.Get(Name, SaveDialog1.FileName, true);
                end;
                mrCancel: begin
                  exit;
                end;
              end;
            end
            else begin
              // 文件不存在的情况
              IdFTP1.Get(Name, SaveDialog1.FileName, false);
            end;
          end;
        finally
          SetFunctionButtons(true);
        end;
      end;
    end;

2.  计算传输平均速度(单位:千字节)的例程:
    procedure TMainForm.IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;
      const AWorkCount: Integer);
    Var
      S: String;
      TotalTime: TDateTime;         // 已传输时间
    //  RemainingTime: 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
        AverageSpeed := {(AverageSpeed + }(AWorkCount / 1024) / DLTime{) / 2};
   
      if AverageSpeed > 0 then begin
        // 根据剩余字节数和平均速度,计算剩余时间
        Sec := Trunc(((ProgressBar1.Max - AWorkCount) / 1024) / AverageSpeed);
   
        S := Format('%2d:%2d:%2d', [Sec div 3600, (Sec div 60) mod 60, Sec mod 60]);
   
        S := 'Time remaining ' + S;
      end
      else S := '';
   
      S := FormatFloat('0.00 KB/s', AverageSpeed) + '; ' + S;
      case AWorkMode of
        wmRead: StatusBar1.Panels[1].Text := 'Download speed ' + S;
        wmWrite: StatusBar1.Panels[1].Text := 'Uploade speed ' + S;
      end;
   
      if AbortTransfer then IdFTP1.Abort;
   
      ProgressBar1.Position := AWorkCount;
      AbortTransfer := false;
    end;
   
3.  限速的例程(收集自INDY的DEMO)
    function TMyDebugger.Recv(var ABuf; ALen: integer): integer;
    var
      LWaitTime: Cardinal;
      LRecvTime: Cardinal;
    begin
      if FBytesPerSecond > 0 then begin
        LRecvTime := IdGlobal.GetTickCount;
        Result := inherited Recv(ABuf, ALen);
        LRecvTime := GetTickDiff(LRecvTime, IdGlobal.GetTickCount);     //得到按实际速度传输所需的毫秒数
        LWaitTime := (Result * 1000) div FBytesPerSecond;               //得到按规定速度传输所需的毫秒数
        if LWaitTime > LRecvTime then begin
          // 实际传输速度快于规定的传输速度,SLEEP相差的毫秒数
          IdGlobal.Sleep(LWaitTime - LRecvTime);
        end;
      end else begin
        // 实际传输速度慢于规定的传输速度,继续传输
        Result := inherited Recv(ABuf, ALen);
      end;
    end;
   
4.  结合了计算平均速度和限速的例程:
    void __fastcall TfrmDllMain::idFtpWork(TObject *Sender,
        TWorkMode AWorkMode, const int AWorkCount)
    {
        char strDebugString[1024];
        TDateTime dtTotalTime;    // 当前文件的实际已传输时间
        Word H,M,Sec,MSec;
        double dTotalTime;        // 当前文件的实际已传输时间,以秒作为单位
        long lCurrentFileTotalTime;     //当前文件的实际已传输时间,以毫秒作为单位
        long lRatedTotalTime;     // 当前文件按额定速度传输,已传输的时间,以毫秒作为单位.
   
        /*
        memset(strDebugString, 0, sizeof(strDebugString));
        sprintf(strDebugString, "--- lStartTransferSize=[%d]", lStartTransferSize);
        OutputDebugString(strDebugString);
        */
   
        lTransferCompleted = lStartTransferSize + AWorkCount;
   
        dtTotalTime =  Now() - dtCurrentFileStartTime;         // 当前文件的实际已传输时间等于当前时间减去当前文件传输开始时间
        DecodeTime(dtTotalTime, H, M, Sec, MSec);   // 把已传输时间拆开成时,分,秒,毫秒
        Sec = Sec + M * 60 + H * 3600;
        dTotalTime = Sec + MSec / 1000;           // 毫秒作为小数部分
        lCurrentFileTotalTime = Sec * 1000 + MSec;           // 以毫秒作为单位
   
        /*
        memset(strDebugString, 0, sizeof(strDebugString));
        sprintf(strDebugString, "--- AWorkCount=[%d]", AWorkCount);
        OutputDebugString(strDebugString);
   
        memset(strDebugString, 0, sizeof(strDebugString));
        sprintf(strDebugString, "--- lTransferCompleted=[%d]", lTransferCompleted);
        OutputDebugString(strDebugString);
        */
   
        if(dTotalTime > 0)
        {
            dAverageSpeed = (dAverageSpeed + AWorkCount / dTotalTime) / 2;
        }
   
        // 对传输速度进行限制.如果额定速度为0,就不限速
        if(lBytesPerSec != 0)
        {
            // 计算以额定速度来传输这些已传输的字节,需要多少时间(单位:毫秒)
            lRatedTotalTime = ((lTransferCompleted - lStartTransferSize) / lBytesPerSec) * 1000;
   
            /*
            memset(strDebugString, 0, sizeof(strDebugString));
            sprintf(strDebugString, "--- lRatedTotalTime=[%ld]", lRatedTotalTime);
            OutputDebugString(strDebugString);
   
            memset(strDebugString, 0, sizeof(strDebugString));
            sprintf(strDebugString, "--- lCurrentFileTotalTime=[%ld]", lCurrentFileTotalTime);
            OutputDebugString(strDebugString);
            */
           
            // 判断实际下载速度是否小于额定下载速度
            if(lRatedTotalTime > lCurrentFileTotalTime)
            {
                // 实际下载速度小于额定下载速度,Sleep相差的毫秒数
                Sleep(lRatedTotalTime - lCurrentFileTotalTime);
            }
        }
   
        /*
        switch(AWorkMode)
        {
            case wmRead:
                memset(strDebugString, 0, sizeof(strDebugString));
                sprintf(strDebugString, "↓↓↓ 下载速度=[%ld]", (long)dAverageSpeed);
                OutputDebugString(strDebugString);
                break;
            case wmWrite:
                memset(strDebugString, 0, sizeof(strDebugString));
                sprintf(strDebugString, "↑↑↑ 上传速度=[%ld]", (long)dAverageSpeed);
                OutputDebugString(strDebugString);
                break;
        }
        */
   
        if(blnAbortTransfer)
        {
            idFtp->Abort();
        }
   
        blnAbortTransfer = false;
   
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值