delphi idftp idhttp 多线程多进度条

    idftp 上传

     多个文件同时上传,支持断点续传,多进度条。

     起初用API做,发现对API了解太少,便改用线程类来处理,代码如下

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属性赋个唯一值,

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;

  将线程与进度条相对应,线程中的变量最好在线程类中定义,每个线程都有一块空间存储变量的值。上代码中

 inherited create(true);       设为true ,所以需要调用TThread.resume来启动线程

 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  , 即一次只准一个线程去调用,以免造成冲突。

posted @ 2012-12-02 15:54  唯一的事  阅读(3323)  评论(0编辑  收藏  举报