IDHTTP:= TIDHTTP.Create(nil);
MyStream:=TMemoryStream.Create;try
    form1.idhttp1.Connect();
  except
  end;  if form1.idhttp1.Connected then
  begin
  try  form1.IdHTTP1.Get('http://dl_dir.qq.com/qqfile/qq2006beta1.exe',MyStream);  filepath:=ExtractFilePath(ParamStr(0));  MyStream.SaveToFile(filepath+'\DownLoadFiles\11.exe');
  MyStream.Free;  showmessage('下载完成!');
  except    showmessage('网络出错未能下载完成!');
    MyStream.Free;
    Exit;
  end;
这是我现在能够成功下载的代码请大家多指点,希望能给一些源码顺便问问怎么能够得到正在下载的文件相关信息,如总大小、下载速度等在onwork的时候可以得到但是我用一个全局变量获得之后好像不能在其他地方用。请各位兄弟们都来参与讨论

解决方案 »

  1.   

    procedure TMyDownLoad.Download;
    Var
      UnitName,PathName:String;
      MyStream:TMemoryStream;
      filepath:string;
      IDHTTP: TIDHttp;begin
    //form1.IDHTTP:= TIDHTTP.Create(nil);
    //form1.StatusBar1.Panels[0].Text:='正在下载文件...';
    IDHTTP:= TIDHTTP.Create(nil);
    MyStream:=TMemoryStream.Create;try
        form1.idhttp1.Connect();
      except
      end;  if form1.idhttp1.Connected then
      begin
      try
      form1.IdHTTP1.Get('http://dl_dir.qq.com/qqfile/qq2006beta1.exe',MyStream);
      filepath:=ExtractFilePath(ParamStr(0));  MyStream.SaveToFile(filepath+'\DownLoadFiles\11.exe');
      MyStream.Free;
      showmessage('下载完成!');
      except
        showmessage('网络出错未能下载完成!');
        MyStream.Free;
        Exit;
      end;end;
    end;constructor TMyDownLoad.Create();
    beginFreeOnTerminate := True; // 自动删除
    InitializeCriticalSection(CS); //初始化临界区
    inherited Create(False); // 直接运行
    end;
    procedure TMyDownLoad.Execute;
    begin
      { Place thread code here }
      EnterCriticalSection(cs);       //进入临界区
      if Terminated then exit;
      Synchronize(Download);
      LeaveCriticalSection(CS);     //退出临界区
    end;这里是我线程工作的主要代码,请问该如何动态添加。可以用一个按钮模拟
      

  2.   

    HTTP协议的:
    procedure TForm1.HttpDownLoad(aURL, afile: string; bResume:Boolean);
    var
      tStream: TFileStream;
    begin //Http方式下载
        if FileExists(aFile) then //如果文件已经存在
          tStream := TFileStream.Create(aFile, fmOpenWrite) 
        else
          tStream := TFileStream.Create(aFile, fmCreate);
        if bResume then //续传方式
        begin
          IdHTTP1.Request.ContentRangeStart := tStream.Size - 1;
          tStream.Position := tStream.Size - 1; //移动到最后继续下载
          IdHTTP1.Head(aURL);
          IdHTTP1.Request.ContentRangeEnd := 
          IdHTTP1.Response.ContentLength;
        end else //覆盖或新建方式
        begin
          IdHTTP1.Request.ContentRangeStart := 0;
        end;
        try
          IdHTTP1.Get(aURL, tStream); //开始下载
        finally
          tStream.Free;
        end;
    end;这里我们同样使用IdHTTP的Get过程,函数的aURL是网址,aFile是保存的文件名,bResume确定是否续传,需要注意的就是续传方式时的代码:
      IdHTTP1.Request.ContentRangeStart := tStream.Size - 1;
      tStream.Position := tStream.Size - 1; //移动到最后继续下载
      IdHTTP1.Head(aURL);
      IdHTTP1.Request.ContentRangeEnd := 
      IdHTTP1.Response.ContentLength;
    第一行我们将下载开始位置设置为读入文件流的末尾,也就是设置为已经下载了的那部分文件的大小,第二行我们将文件流本身也指向自己的末尾,第三行我们通过Head过程得到网址头信息,在第四行将头信息的文件总大小赋值给下载的结束的位置,至于这里为什么第一行和第二行代码最后都要-1,我当时没有加-1的时候在续下载一个完整的已经下载的文件的时候总是提示错误,最后跟踪IdHTTP的代码发现他在处理下载范围的时候如果开始的位置和结束位置一样时会引发将浮点数转为整数的错误,因而这里加上-1防止这种错误发生,另外一种处理方法就是比较如果开始位置等于结束位置就退出也是可以的。
    再来看FTP协议的下载过程:
    procedure TForm1.FtpDownLoad(aURL, afile: string; bResume: Boolean);
    var
      tStream: TFileStream;
      sName, sPass, sHost, sPort, sDir: string;
    begin //ftp方式下载
      if FileExists(aFile) then //建立文件流
      tStream := TFileStream.Create(aFile, fmOpenWrite) else
      tStream := TFileStream.Create(aFile, fmCreate);
      GetFTPParams(aURL, sName, sPass, sHost, sPort, sDir);
      with IdFTP1 do
      try
        if Connected then Disconnect; //重新连接
        Username := sName;
        Password := sPass;
        Host := sHost;
        Port := StrToInt(sPort);
        Connect;
      except
        exit;
      end;
      IdFTP1.ChangeDir(sDir); //改变目录
      BytesToTransfer := IdFTP1.Size(aFile);
      try
        if bResume then //续传
        begin
          tStream.Position := tStream.Size;
          IdFTP1.Get(aFile, tStream, True);
        end else
        begin
          IdFTP1.Get(aFile, tStream, False);
        end;
      finally
        tStream.Free;
      end;
    end;
    这个过程中我们就用到了GetFTPParams()函数将网址的用户名、密码、主机地址、端口、路径等信息分离出来,IdFTP利用这些信息登陆服务器并到相应目录,最后利用Get()过程就很容易实现下载了,它的续传就比HTTP协议要简单很多,因为IdFTP的Get()本身就支持续传。
    这里我简单穿插一点的内容,一个服务器是否支持断点续传,我们可以通过发送REST 1FTP指令来检测,如果返回350则表示支持。
    最后我们根据网址来确定使用什么协议来下载:
    function TForm1.GetProt(aURL: string): Byte;
    begin //检测下载的地址是http还是ftp
      Result := 0;
      if Pos('http', LowerCase(aURL)) = 1 then
        Result := 1; //http协议
      if Pos('ftp', LowerCase(aURL)) = 1 then
        Result := 2; //ftp协议
    end;
    这个函数根据网址返回整数供我们使用。
    procedure TForm1.MyDownLoad(aURL, afile: string; bResume: Boolean);
    begin
      case GetProt(aURL) of
        0: ShowMessage('不可识别的地址!');
        1: HttpDownLoad(aURL, aFile, bResume);
        2: FtpDownLoad(aURL, aFile, bResume);
      end;
    end;
    这个过程就利用GetProt()函数返回的整数执行相应的协议下载过程。
    接下来看看每个按钮的代码,有了上面的函数,按钮的代码就简单多了:
    下载按钮:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      aURL, afile: string;
    begin
      aURL := ComboBox1.Text; //下载地址
      aFile := GetURLFileName(aURL); //得到文件名,例如demo.exe
      if FileExists(aFile) then
      begin
        case MessageDlg('文件已经存在,是否续传?', mtConfirmation, mbYesNoCancel,0) of
          mrYes: MyDownLoad(aURL, aFile, True); //续传
          mrNo: MyDownLoad(aURL, aFile, False); //覆盖
          mrCancel: Exit; //取消
        end;
      end else MyDownLoad(aURL, aFile, False); //建立新文件下载
    end;
    MessageDlg()函数弹出一个对话框让用户选择续传、覆盖还是取消下载。
    中断按钮:
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      AbortTransfer := True;
    end;
    前面忘了介绍,所以这里大家看不明白,AbortTransfer是我们定义的一个私有变量,在开始下载的时候将它设为False,下载的过程中随时监测这个变量,一旦变为True就利用IdHTTP的Disconnect和IdFTP1的Abort方法中断下载,如果没有下载完就中断,那程序的目录中就会有一个下载不完整的程序或者其他东西,下次再下载的时候我们就可以选择续传来完成剩下的下载过程。
    procedure TForm1.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;const AWorkCountMax: Integer);
    begin
      AbortTransfer := False;
      ……
      end;
    在IdHTTP1和IdFTP的OnWorkBegin事件我们就将AbortTransfer设置为False了,在他们的Work事件中,我们检测AbortTransfer变量来完成是否中断的操作。
    procedure TForm1.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;const AWorkCount: Integer);
    begin
      if AbortTransfer then
      begin //中断下载
        IdHTTP1.Disconnect;
        IdFTP1.Abort;
      end;
      ProgressBar1.Position := AWorkCount;
      Application.ProcessMessages;
    end;
    最后是连接状态等信息的代码:
    在IdHTTP和IdFTP的OnStatus事件写入:
    procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;const AStatusText: string);
    begin
      ListBox1.ItemIndex := ListBox1.Items.Add(AStatusText);
    end;
    因为IdHTTP和IdFTP在OnWork、OnStatus等事件上执行的代码都是一样的,所以我们只用写其中一个的代码,然后另外一个选择相同的事件就OK了。ZT