delphi idftp idhttp 多線程多進度條

idftp 上傳數據庫

     多個文件同時上傳,支持斷點續傳,多進度條。服務器

     起初用API作,發現對API瞭解太少,便改用線程類來處理,代碼以下ide

TThread1 = class(TThread)
 private
   fCount, tstart, tlast: integer;
   tURL, tFile, temFileName,temLocalFile: string;
   tResume: Boolean;
   tStream: TFileStream;
   temFtp: TIdFTP;
   sFileName: string;
   pb: TProgressBar;
   bstate:Integer;  //1,表示準備上傳,2表示正在上傳,3表示上傳完成,4表示上傳失敗函數

 protected
   procedure Execute; override;
 public
   constructor create1(aURL, aFile, fileName,localfile: string; bResume: Boolean; Count,
     start, last: integer);
   procedure DownLodeFile(); //上傳文件
  // function SetProgressInListView(lvw: TListView): Boolean; //在listview中動態建立進度條
   procedure StateChange;       //上傳狀態改變
   procedure FtpUp;
 end;線程

  建立線程以前把進度條動態建立好,給進度條的Tag屬性賦個惟一值,orm

for i:=0 to iCount-1 do
  begin
    SetProgressInListView(ListView1,i,1,10,3);  //   建立進度條
    localfile:=ListView1.Items.Item[i].Caption;
    MyThread[i+1] := TThread1.create1('', '', '',localfile, false,i,2,1);
  end;同步

 

constructor TThread1.create1(aURL, aFile, fileName,localfile: string; bResume: Boolean;
 Count, start, last: integer);
var
   i:Integer;
begin
  inherited create(true);     //設置爲true 主要是爲了調用resume  即建立線程時先不執行,調用thread1.resume執行線程。
  freeonterminate:=true;
  tURL := aURL;
  tFile := aFile;
  fCount := Count;
  tResume := bResume;
  tstart := start;
  tlast := last;
  temFileName := fileName;
  temLocalFile:=localfile;
  for i:=0 to  Form1.ComponentCount-1 do
  begin                                                       //將建好的進度條與線程先對應
    if Form1.Components[i] is TProgressBar then
      if Form1.Components[i].Tag=fcount then
      begin
        pb:=TProgressBar(Form1.Components[i]);
      end;
   end;
end;string

  將線程與進度條相對應,線程中的變量最好在線程類中定義,每一個線程都有一塊空間存儲變量的值。上代碼中it

 inherited create(true);       設爲true ,因此須要調用TThread.resume來啓動線程io

 while j <= iCount do
     begin
       MyThread[j].Resume; //喚醒線程
       j := j + 1;

     end;

線程執行函數:  執行一次線程,動態建立一個IDFTP控件,將本地文件存成一個流,若是大於1M,則分段截取傳送。

procedure TThread1.DownLodeFile();
const
  SEND_BUFFER=1048576;// 一次提交1M的東西
var
 AFileStream: TFileStream;
 AsFileStream: TMemoryStream;
begin
  bstate:=1;
  Synchronize(StateChange);
  try
    temFtp := TIdFTP.Create(nil);
    temFtp.Host:=Form1.IPEdit.Text;
    temFtp.Username:=Form1.NameEdit.Text;
    temFtp.Password:=Form1.PwdEdit.Text;
    temFtp.Port:=StrToInt(Form1.PortEdit.Text);
    temFtp.Connect;
    temFtp.onWorkBegin := Form1.IdFTP1WorkBegin;
    temFtp.onwork := Form1.IdFTP1work;
    sFileName := ExtractFileName(temLocalFile);
    AFileStream := TFileStream.Create(temLocalFile, fmOpenRead);
 //   temFtp.ChangeDir('LoacalUser');  //改變服務器端目錄
    try
//  獲取斷點
      AFileStream.Seek(temFtp.Size(sFileName), soFromBeginning);
// 開始斷點續傳
      AsFileStream:= TMemoryStream.Create;
      pb.Max:=AFileStream.Size;       //進度條賦值
      pb.min:=0;
      bstate:=2;
      Synchronize(StateChange);
      try
        while (AFileStream.Position < AFileStream.Size) do
        begin
          sleep(300);       //等待時間太長
          AsFileStream.Clear;
          AsFileStream.CopyFrom(AFileStream, Min(SEND_BUFFER, AFileStream.Size - AFileStream.Position));
      //  AsFileStream.CopyFrom(AFileStream,AFileStream.Size - AFileStream.Position);
          AsFileStream.Position:=0;
          temFtp.Put(AsFileStream, sFileName, true);
          pb.Position:=AFileStream.Position;

        end;
          pb.Position:=AFileStream.Size;
          bstate:=3;
          Synchronize(StateChange);
          AsFileStream.Free;
          AFileStream.free;
      except
        bstate:=4;
        Synchronize(StateChange);
        AsFileStream.Free;
        AFileStream.free;
        raise;
      end;
// 判斷是否上傳完畢
   {  if AFileStream.Position = AFileStream.Size then
       ShowMessage('上傳完畢!')
      else
        ShowMessage('下次記得繼續續傳~');
      synchronize(StateChange(true));
      AFileStream.Free;
      }

    except
      bstate:=4;
      Synchronize(StateChange);
      AFileStream.Free;
     // ShowMessage('出錯... - -');
    end;

  finally
    Synchronize(FtpUp);         //添加到數據庫
      temFtp.free;
  end;
end;

當線程須要調用窗口的控件時,最好同步Synchronize  , 即一次只准一個線程去調用,以避免形成衝突。

相關文章
相關標籤/搜索