• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 798
  • Last Modified:

download a file from a website

I want to download a file from a website let's say x.com/files/down.zip (around 5mb) to my computer but with this options.
1. to get the size of the file
2. to start download, stop it and resume it
3. to show a progressbar and how much was downloaded


I've tried using idhttp from indy 9.0 but when downloading the program does,nt respond until finished and i didn't find a way to make the above steps.

I try to make a small installer and download a file from a site and opening.

Any help would be apreciated

dia21
0
dia21
Asked:
dia21
  • 6
  • 5
  • 2
  • +2
1 Solution
 
Eddie ShipmanAll-around developerCommented:
Use ICS as it uses non-blocking sockets unlike Indy.

http://www.overbyte.be/frame_index.html
0
 
DragonSlayerCommented:
Check out this sample for resuming download (and multi-segment downloads using multiple threads) http://codecentral.borland.com/codecentral/ccweb.exe/download?id=17604

0
 
dia21Author Commented:
EddieShipman i don't want to use a shareware component

DragonSlayer i can't download it or see what is there
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
dia21Author Commented:
DragonSlayer please give me another location or the code because i get this "Internal Application Error" when visiting your site
0
 
vaceroseCommented:
Indy Blocking Workaround
If you look on the "Indy Misc" component tab there is a component called TIdAntifreeze.  Add this component to your app and the the "OnlyWhenIdle" property to false.  This will cause Indy to call ProcessMessages during the download allowing you to call the http component "Disconnect" method when a button is clicked.  You should wrap the Get method in an exception handler to deal with the disconnect gracefully.

Indy HTTP progress
The indy HTTP component has 2 events you need for the progress display.  In OnWorkBegin save the AWorkCountMax parameter to a global variable, this is the total byte count. I prefer to assign it to the Tag property of the http component.  In OnWork, the AWorkCount parameter is the number of bytes downloaded so far.

Indy Resume
Sorry I can't help you with the resume. I'm not sure it is possible with Indy 9
0
 
DragonSlayerCommented:
0
 
Eddie ShipmanAll-around developerCommented:
Pardon me but ICS is FREE, just like Indy. Did you EVEN check it out?
0
 
dia21Author Commented:
EddieShipman you're right. I did checked the link but i saw the purchase link and i thought that is shareware, sorry:)
I downloaded now and i'll take a look
0
 
TheRealLokiSenior DeveloperCommented:
There are a number of ways to do this, below is a simple code snippit that will give you an idea of how to do this. Make sure to add ShellApi, and UrlMon to your uses clause.

function DownLoadInternetFile(Source, Dest : String): Boolean;
begin
  try
    Result := URLDownloadToFile(nil,PChar(Source),PChar(Dest),0,nil) = 0
  except
    Result := False;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  SourceString, DestinationString: string;
begin
//File location on the Internet.
  SourceString := 'http://www.borland.com/images/homepage/del6homemural.gif';
//File destination.
  DestinationString := 'C:Tempdel6homemural.gif';

  if DownLoadInternetFile(SourceString, DestinationString) then
//This will display the file from your browser.
    ShellExecute(Application.Handle, PChar('Open'), PChar(DestinationString), PChar(''), nil, SW_NORMAL)
  else
    ShowMessage('Error during Download ' + SourceString);
end;
0
 
TheRealLokiSenior DeveloperCommented:
here's a real quick demo I wrote for you, showing the download and progress


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdHTTP, IdAntiFreezeBase, IdAntiFreeze;
// By }-=Loki=-{ lokiwashere@yahoo.co.nz
type
  TForm1 = class(TForm)
    IdHTTP1: TIdHTTP;
    ProgressBar1: TProgressBar;
    Button1: TButton;
    eFilename: TEdit;
    Label2: TLabel;
    IdAntiFreeze1: TIdAntiFreeze;
    procedure Button1Click(Sender: TObject);
    procedure IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
      const AWorkCountMax: Integer);
    procedure IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
      const AWorkCount: Integer);
  private
    { Private declarations }
    TotalFilesize: Integer;
    function GetFilenameFromAddress(s: string): string;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

IMPLEMENTATION

{$R *.DFM}

function TForm1.GetFilenameFromAddress(s: string): string;
    begin
        S := StringReplace(S, '/', '\', [rfReplaceAll]);
        result := ExtractFileName(S);
    end;

procedure TForm1.Button1Click(Sender: TObject);
    var
        fs: TStream;
    begin
        fs := TFileStream.Create(ExtractFilePath(Paramstr(0)) + GetFilenameFromAddress(eFilename.Text), fmCreate);
        try
            IdHTTP1.Get(eFilename.text, fs);
        finally
            fs.free;
        end;
        ShowMessage('completed');
    end;

procedure TForm1.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
    const AWorkCountMax: Integer);
    begin
        ProgressBar1.Max := AWorkCountMax;
        ProgressBar1.Position := 0;
    end;

procedure TForm1.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
    const AWorkCount: Integer);
    begin
        ProgressBar1.StepBy(AWorkCOunt);
        ProgressBar1.Repaint;
    end;

end.


/// FORM FOLLOWS

object Form1: TForm1
  Left = 274
  Top = 168
  Width = 392
  Height = 191
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label2: TLabel
    Left = 24
    Top = 24
    Width = 42
    Height = 13
    Caption = 'Filename'
  end
  object ProgressBar1: TProgressBar
    Left = 8
    Top = 112
    Width = 321
    Height = 16
    Min = 0
    Max = 100
    TabOrder = 0
  end
  object Button1: TButton
    Left = 8
    Top = 80
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
  end
  object eFilename: TEdit
    Left = 96
    Top = 16
    Width = 241
    Height = 21
    TabOrder = 2
    Text = 'http://torry.net/images/h2-1.gif'
  end
  object IdHTTP1: TIdHTTP
    MaxLineAction = maException
    OnWork = IdHTTP1Work
    OnWorkBegin = IdHTTP1WorkBegin
    AllowCookies = True
    ProxyParams.BasicAuthentication = False
    ProxyParams.ProxyPort = 0
    Request.ContentLength = -1
    Request.ContentRangeEnd = 0
    Request.ContentRangeStart = 0
    Request.ContentType = 'text/html'
    Request.Accept = 'text/html, */*'
    Request.BasicAuthentication = False
    Request.UserAgent = 'Mozilla/3.0 (compatible; Indy Library)'
    HTTPOptions = [hoForceEncodeParams]
    Left = 160
    Top = 72
  end
  object IdAntiFreeze1: TIdAntiFreeze
    Left = 200
    Top = 72
  end
end
0
 
TheRealLokiSenior DeveloperCommented:
I can show you how to resume by using Francois Piette's ICS, it's as simple as
    httpcli1.ContentRangeBegin := IntToStr(httpcli1.ContentLength - 100);
    httpcli1.ContentRangeBegin := IntToStr(httpcli1.ContentLength);
    httpcli1.Get;
(this would get the last 100 bytes)
and the progress is pretty straight forward. You should be able to suss it out from the demos
0
 
dia21Author Commented:
TheRealLoki
the resume it's working but it stil downloads from the server the entire server and it writes on my computer from the last 100 bytes. I want that download from where it stoped. In the way from your code it's the same thing as if i would download it again. have any sugestions an how to fix this?

as the progress i didn't find in the demos with ics
0
 
TheRealLokiSenior DeveloperCommented:
to resume, what you'd do is open the partial file, get the "partialfilesize"
(e.g. open it as a TFileStream and check the size, plenty of examples of that elsewhere)
and read (append) from there

e.g. ContentRangeBegin := partialfilesize

Update the progress bar in the OnDocData event, or the OnSendData event
0
 
dia21Author Commented:
It still doesn't work the resume. The ics downloads the entire file and it updates my file when it arrives at the corrct size.
Here is the code that i use maybe i do something wrong.

procedure TForm1.Button1Click(Sender: TObject);

function swapSlash(text:String):String;
begin
  text := StringReplace(text, '/', '\', [rfReplaceAll]);
        result := ExtractFileName(text);
end;

var result:String;
    ms:TFileStream;
    exists:boolean;
begin
    button2.Enabled:=True;
    Debuglistbox.Items.Clear;
    result:=ExtractFilepath(ParamStr(0))+ExtractFilename(swapslash(url));
    httpcli1.URL:=url;
    if Fileexists(result) then
    begin
        exists:=True;
       httpcli1.RcvdStream:=TFileStream.Create(result,fmOpenWrite);
    end
         else begin exists:=False;
             httpcli1.RcvdStream:=TFileStream.Create(result,fmCreate);
            end;
    Button1.Enabled:=False;
    Debuglistbox.Items.Add('Connecting...');
    try
      try
      if exists then
        begin
          Debuglistbox.Items.Add('File already exists. Resuming ...');
          httpcli1.ContentRangeBegin:=IntToStr(httpcli1.RcvdStream.Size);

        end;
        progressbar1.Max:=1163722;
        httpcli1.Get;
        Label1.Caption:='Received: '+ IntToStr(ceil(httpcli1.RcvdStream.Size/1024))+ ' kb';
      except
      on E: EHttpException do begin
                Label1.Caption := 'Failed : ' +
                                     IntToStr(HttpCli1.StatusCode) + ' ' +
                                     HttpCli1.ReasonPhrase;;
            end
            else
                raise;
        end;
    finally
   Button1.Enabled:=True;
   button2.Enabled:=False;
   label1.Caption:='';
   HttpCli1.RcvdStream.Destroy;
   HttpCli1.RcvdStream := nil;
end;
end;
0
 
TheRealLokiSenior DeveloperCommented:
The _server_ has to support resumes, If it does not, then yes, it will download the entire file
0
 
dia21Author Commented:
but the code is correct?
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

  • 6
  • 5
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now