1. unit Unit1;
  2. interface
  3. uses
  4.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  5.   Dialogs, ComCtrls, StdCtrls, IdComponent, IdTCPConnection, IdTCPClient,
  6.   IdHTTP, IdBaseComponent, IdAntiFreezeBase, IdAntiFreeze,
  7.   IdThreadComponent, IdFTP ,IdException;
  8. type
  9.   MyException1 = class(exception)//自定义的异常类
  10. end;
  11. type
  12.   TThread1 = class(TThread)
  13.   private
  14.     fCount, tstart, tlast: integer;
  15.     tURL, tFile, temFileName: string;
  16.     tResume: Boolean;
  17.     tStream: TFileStream;
  18.   protected
  19.     procedure Execute; override;
  20.   public
  21.     constructor create1(aURL, aFile, fileName: string; bResume: Boolean; Count,
  22.       start, last: integer);
  23.     procedure DownLodeFile(); //下载文件
  24.   end;
  25. type
  26.   TForm1 = class(TForm)
  27.     IdAntiFreeze1: TIdAntiFreeze;
  28.     IdHTTP1: TIdHTTP;
  29.     Button1: TButton;
  30.     ProgressBar1: TProgressBar;
  31.     Label1: TLabel;
  32.     Label2: TLabel;
  33.     Button2: TButton;
  34.     Button3: TButton;
  35.     ListBox1: TListBox;
  36.     Edit1: TEdit;
  37.     Edit2: TEdit;
  38.     Label3: TLabel;
  39.     Label4: TLabel;
  40.     Label5: TLabel;
  41.     SaveDialog1: TSaveDialog;
  42.     procedure Button1Click(Sender: TObject);
  43.     procedure IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
  44.       const AWorkCountMax: Integer);
  45.     procedure IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
  46.       const AWorkCount: Integer);
  47.     procedure Button2Click(Sender: TObject);
  48.     procedure IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;
  49.       const AStatusText: string);
  50.     procedure Button3Click(Sender: TObject);
  51.   private
  52.   public
  53.     nn, aFileSize, avg: integer;
  54.     time1, time2: TDateTime;
  55.     MyThread: array[1..10of TThread;
  56.     procedure GetThread();
  57.     procedure AddFile();
  58.     procedure NewAddFile();
  59.     function GetURLFileName(aURL: string): string;
  60.     function GetFileSize(aURL: string): integer;
  61.   end;
  62. var
  63.   Form1: TForm1;
  64. implementation
  65. var
  66.   AbortTransfer: Boolean;
  67.   aURL, aFile: string;
  68.   tcount: integer//检查文件是否全部下载完毕
  69. {$R *.dfm}
  70.   //get FileName
  71. function TForm1.GetURLFileName(aURL: string): string;
  72. var
  73.   i: integer;
  74.   s: string;
  75. begin //返回下载地址的文件名
  76.   s := aURL;
  77.   i := Pos('/', s);
  78.   while i <> 0 do //去掉"/"前面的内容剩下的就是文件名了
  79.   begin
  80.     Delete(s, 1, i);
  81.     i := Pos('/', s);
  82.   end;
  83.   Result := s;
  84. end;
  85. //get FileSize
  86. function TForm1.GetFileSize(aURL: string): integer;
  87. var
  88.   FileSize: integer;
  89. begin
  90.   IdHTTP1.Head(aURL);
  91.   FileSize := IdHTTP1.Response.ContentLength;
  92.   IdHTTP1.Disconnect;
  93.   Result := FileSize;
  94. end;
  95. //执行下载
  96. procedure TForm1.Button1Click(Sender: TObject);
  97. var
  98.   j: integer;
  99. begin
  100.     //savedialog1.
  101.   try
  102.     time1 := Now;
  103.     tcount := 0;
  104.     aURL := Edit1.Text; //下载地址
  105.     if aURL = '' then
  106.     begin
  107.        MessageDlg('请输入下载地址!',mtError,[mbOK],0);
  108.        Exit;
  109.     end;
  110.     aFile := GetURLFileName(Edit1.Text); //得到文件名
  111.     savedialog1.FileName :=afile;
  112.     if savedialog1.Execute then
  113.     if Edit2.Text = '' then
  114.     begin
  115.       case MessageDlg('请输入线程数,最大支持10个线程,默认为单线程下载!', mtConfirmation, [mbYes, mbNo], 0of
  116.         mrYes: nn:=1//默认
  117.         mrNo: Exit; //重新输入
  118.       end;
  119.     end
  120.     else
  121.       nn := StrToInt(Edit2.Text); //线程数
  122.       if nn > 10 then
  123.       begin
  124.         raise MyException1.Create('输入超过线程限制数,请重新输入!');
  125.       end;
  126.       j := 1;
  127.       aFileSize := GetFileSize(aURL);
  128.       avg := trunc(aFileSize / nn);
  129.       begin
  130.         try
  131.           GetThread();
  132.           while j <= nn do
  133.           begin
  134.             MyThread[j].Resume; //唤醒线程
  135.             j := j + 1;
  136.           end;
  137.         except
  138.           Showmessage('创建线程失败!');
  139.           Exit;
  140.         end;
  141.       end;
  142.   except
  143.     on E:EConvertError do//捕捉内建的Econverterror异常
  144.     begin
  145.       //ShowMessage('请输入数字');
  146.       MessageDlg('请输入数字'+#13,mtError,[mbOK],0);
  147.       Exit;
  148.     end;
  149.     on E:MyException1 do//捕捉自定义的MyException异常
  150.     begin
  151.       MessageDlg(E.Message,mtError,[mbOK],0);
  152.       Edit2.Text:= '';
  153.       Exit;
  154.     end;
  155.     on E:EIdSocketError do//捕捉内建的EIdSocketError异常
  156.     begin
  157.       MessageDlg('连接不上服务器,或服务起未开启!',mtError,[mbOK],0);
  158.       Exit;
  159.     end;
  160.     on E:EIdConnectException do//捕捉内建的EIdSocketError异常
  161.     begin
  162.       MessageDlg('连接不上服务器,或服务起未开启!',mtError,[mbOK],0);
  163.       Exit;
  164.     end;
  165.     on E:EIdHTTPProtocolException do//捕捉内建的EIdSocketError异常
  166.     begin
  167.       MessageDlg('目标文件找不到!',mtError,[mbOK],0);
  168.       Exit;
  169.     end;
  170.   else
  171.     raise //reraise其他异常
  172.   end;
  173. end;
  174. //开始下载前,将ProgressBar1的最大值设置为需要接收的数据大小.
  175. procedure TForm1.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
  176.   const AWorkCountMax: Integer);
  177. begin
  178.   AbortTransfer := true;
  179.   ProgressBar1.Max := AWorkCountMax;
  180.   ProgressBar1.Min := 0;
  181.   ProgressBar1.Position := 0;
  182. end;
  183. //接收数据的时候,进度将在ProgressBar1显示出来.
  184. procedure TForm1.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
  185.   const AWorkCount: Integer);
  186. begin
  187.   if AbortTransfer then
  188.   begin
  189.     //IdHTTP1.Disconnect; //中断下载
  190.   end;
  191.   ProgressBar1.Position := AWorkCount;
  192.   //ProgressBar1.Position:=ProgressBar1.Position+AWorkCount; //*******显示速度极快
  193.   Application.ProcessMessages;
  194.   //***********************************这样使用不知道对不对
  195. end;
  196. //中断下载
  197. procedure TForm1.Button2Click(Sender: TObject);
  198. var
  199.   i : integer;
  200. begin
  201.   try
  202.     if AbortTransfer then
  203.       begin
  204.         i:=1;
  205.         while i <= nn do
  206.           begin
  207.           MyThread[i].Suspend;
  208.           i := i + 1;
  209.            end;
  210.        AbortTransfer := false;
  211.        button2.Caption:='开始';
  212.    end else
  213.      begin
  214.      i:=1;
  215.      while i <= nn do
  216.        begin
  217.        MyThread[i].Resume;
  218.        i := i + 1;
  219.        end;
  220.       AbortTransfer := True;
  221.      button2.Caption:='暂停';
  222.     end;
  223.   except
  224.     on E:EThread do
  225.     begin
  226.     end;
  227.   else
  228.     raise //reraise其他异常
  229. end;
  230.   //IdHTTP1.Disconnect;
  231. end;
  232. //状态显示
  233. procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;
  234.   const AStatusText: string);
  235. begin
  236.   ListBox1.ItemIndex := ListBox1.Items.Add(AStatusText);
  237. end;
  238. //退出程序
  239. procedure TForm1.Button3Click(Sender: TObject);
  240. begin
  241.   //application.Terminate;
  242.   IdHTTP1.DisconnectSocket;
  243.   Form1.close;
  244. end;
  245. //循环产生线程
  246. procedure TForm1.GetThread();
  247. var
  248.   i: integer;
  249.   start: array[1..100of integer;
  250.   last: array[1..100of integer;   //改用了数组,也可不用
  251.   fileName: string;
  252. begin
  253.   i := 1;
  254.   while i <= nn do
  255.   begin
  256.     start[i] := avg * (i - 1);
  257.     last[i] := avg * i -1//这里原先是last:=avg*i;
  258.     if i = nn then
  259.     begin
  260.       last[i] := avg*i + aFileSize-avg*nn; //这里原先是aFileSize
  261.     end;
  262.     fileName := aFile + IntToStr(i);
  263.     MyThread[i] := TThread1.create1(aURL, aFile, fileName, false, i, start[i],
  264.       last[i]);
  265.     i := i + 1;
  266.   end;
  267. end;
  268. procedure TForm1.AddFile(); //合并文件
  269. var
  270.   mStream1, mStream2: TMemoryStream;
  271.   i: integer;
  272. begin
  273. try
  274.   i := 1;
  275.   mStream1 := TMemoryStream.Create;
  276.   mStream2 := TMemoryStream.Create;
  277.   mStream1.loadfromfile(afile + '1');
  278.   while i < nn do
  279.   begin
  280.     mStream2.loadfromfile(afile + IntToStr(i + 1));
  281.     mStream1.seek(mStream1.size, soFromBeginning);
  282.     mStream1.copyfrom(mStream2, mStream2.size);
  283.     mStream2.clear;
  284.     i := i + 1;
  285.   end;
  286.   FreeAndNil(mStream2);
  287.   mStream1.SaveToFile(afile);
  288.   FreeAndNil(mStream1);
  289.   //删除临时文件
  290.   i:=1;
  291.    while i <= nn do
  292.   begin
  293.     deletefile(afile + IntToStr(i));
  294.     i := i + 1;
  295.   end;
  296.   Form1.ListBox1.ItemIndex := Form1.ListBox1.Items.Add('下载成功');
  297. except
  298.     i:=1;
  299.     while i <= nn do
  300.     begin
  301.     if FileExists(aFile+inttostr(i)) then
  302.     deletefile(afile + IntToStr(i));
  303.     i := i + 1;
  304.     end;
  305.     ShowMessage('下载文件出错,临时文件已删除,请重新下载!')
  306.   end;
  307. end;
  308. procedure TForm1.NewAddFile(); //合并文件
  309. var
  310.   i: Integer;
  311.   InStream, OutStream : TFileStream;
  312.   SourceFile : String;
  313. begin
  314.   try
  315.     i := 1;
  316.     OutStream:=TFileStream.Create(aFile,fmCreate);
  317.     //OutStream:=TFileStream.Create(('D\1\'+aFile),fmCreate); //此句与savedialog冲突,发生异常,使savedialog指定路径无效。
  318.     while i <= nn do
  319.     begin
  320.       SourceFile := afile + IntToStr(i);
  321.       InStream:=TFileStream.Create(SourceFile, fmOpenRead);
  322.       OutStream.CopyFrom(InStream,0);
  323.       FreeAndNil(InStream);
  324.       i:= i+1;
  325.     end;
  326.     FreeAndNil(OutStream);
  327.     //删除临时文件
  328.     i:=1;
  329.     while i <= nn do
  330.     begin
  331.     deletefile(afile + IntToStr(i));
  332.     i := i + 1;
  333.     end;
  334.   except
  335.     i:=1;
  336.     while i <= nn do
  337.     begin
  338.     if FileExists(aFile+inttostr(i)) then
  339.     deletefile(afile + IntToStr(i));
  340.     i := i + 1;
  341.     end;
  342.   end;
  343.   if FileExists(aFile) then
  344.   begin
  345.     FreeAndNil(OutStream);
  346.     InStream := TFileStream.Create(aFile, fmOpenWrite);
  347.     if InStream.Size < aFileSize then
  348.     begin
  349.       FreeAndNil(InStream);
  350.       deletefile(afile);
  351.       //ShowMessage('下载文件出错,临时文件已删除,请重新下载!')
  352.       Form1.ListBox1.ItemIndex := Form1.ListBox1.Items.Add('下载文件出错,临时文件已删除,请重新下载!');
  353.     end
  354.     else
  355.     begin
  356.       FreeAndNil(InStream);
  357.       Form1.ListBox1.ItemIndex := Form1.ListBox1.Items.Add('下在成功');
  358.     end;
  359.   end;
  360.   
  361. end;
  362. //构造函数
  363. constructor TThread1.create1(aURL, aFile, fileName: string; bResume: Boolean;
  364.   Count, start, last: integer);
  365. begin
  366.   inherited create(true);
  367.   FreeOnTerminate := true;
  368.   tURL := aURL;
  369.   tFile := aFile;
  370.   fCount := Count;
  371.   tResume := bResume;
  372.   tstart := start;
  373.   tlast := last;
  374.   temFileName := fileName;
  375. end;
  376. //下载文件函数
  377. procedure TThread1.DownLodeFile();
  378. var
  379.   temhttp: TIdHTTP;
  380. begin
  381.   temhttp := TIdHTTP.Create(nil);
  382.   temhttp.onWorkBegin := Form1.IdHTTP1WorkBegin;
  383.   temhttp.onwork := Form1.IdHTTP1work;
  384.   temhttp.onStatus := Form1.IdHTTP1Status;
  385.   Form1.IdAntiFreeze1.OnlyWhenIdle := False; //设置使程序有反应.
  386.   if FileExists(temFileName) then //如果文件已经存在
  387.     tStream := TFileStream.Create(temFileName, fmOpenWrite)
  388.   else
  389.     tStream := TFileStream.Create(temFileName, fmCreate);
  390.   if tResume then //续传方式
  391.   begin
  392.     exit;
  393.   end
  394.   else //覆盖或新建方式
  395.   begin
  396.     temhttp.Request.ContentRangeStart := tstart;
  397.     temhttp.Request.ContentRangeEnd := tlast;
  398.   end;
  399.   try
  400.     ///try
  401.       temhttp.Get(tURL, tStream); //开始下载
  402.     except
  403.       if FileExists(temFileName) then
  404.       begin
  405.       freeandnil(tstream);
  406.       deletefile(temFileName);//本来想用来删除未下完的文件,可惜不成功,有的线程没有删除,只有部分删除了,
  407.                               //不过这样导致后面合并文件时出错,同样也可以把临时文件删除。
  408.       //ShowMessage('下载文件出错,临时文件已删除,请重新下载!');/
  409.       end;
  410.       temhttp.Disconnect;
  411.     end;
  412.     Form1.ListBox1.ItemIndex := Form1.ListBox1.Items.Add(temFileName +
  413.       'download');
  414.   //finally
  415.     freeandnil(tstream);
  416.     temhttp.Disconnect;
  417.   //end;
  418. end;
  419. procedure TThread1.Execute;
  420. begin
  421.   if Form1.Edit1.Text <> '' then
  422.     //synchronize(DownLodeFile)
  423.     DownLodeFile
  424.   else
  425.     exit;
  426.   inc(tcount);
  427.   if tcount = Form1.nn then //当tcount=nn时代表全部下载成功
  428.   begin
  429.     Form1.ListBox1.ItemIndex := Form1.ListBox1.Items.Add('正在合并删除临时文件');
  430.     Form1.NewAddFile;
  431.     form1.time2 := Now;
  432.     Form1.Label5.Caption := FormatDateTime ('n:ss', form1.Time2-Form1.Time1) + ' seconds';
  433.   end;
  434. end;
  435. end.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/flashrhx2007/archive/2008/08/24/2823153.aspx

posted on 2011-04-08 11:50  sunjun0427  阅读(907)  评论(0编辑  收藏  举报