多線程idhttp下載文件源代碼

 
  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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章