AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Internet Downloads verschiedene Get() Varianten
Thema durchsuchen
Ansicht
Themen-Optionen

Internet Downloads verschiedene Get() Varianten

Ein Thema von KodeZwerg · begonnen am 29. Apr 2018 · letzter Beitrag vom 1. Mai 2018
Antwort Antwort
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#1

Internet Downloads verschiedene Get() Varianten

  Alt 29. Apr 2018, 10:53
Hallo Leute,

in diesem Beispiel Projekt stelle ich euch 3 verschiedene Get( URL ) Möglichkeiten vor die keine speziellen Komponenten erfordern, alles arbeitet bei Laufzeit.
Es wird HTTP und HTTPS unterstützt.
Es wird Unicode unterstützt.
Man kann auf zwei Arten speichern, entweder das Original oder die Memo-Kopie.
Es ist nicht perfekt, aber zeigt einem wie einfach man an dieses Ziel gelangen kann.
Es wird entweder eine Datei empfangen oder der HTML Sourcecode.
internetdownloader.jpg
In der zweiten Uses Klausel ist für jede der 4 Download Varianten chronologisch die Unit enthalten die diese Funktion ermöglicht.
Bei Bedarf einfach nur die entsprechende Funktion herauskopieren und in euer Projekt bereitstellen, Uses anpassen, fertig.
Die TDownloadURL Methode springt dabei etwas aus der Reihe, dabei muss im Vorfeld ein Dateiname zum speichern angegeben werden.

Hier der Projekt Quell-Code, im Anhang das fertige Demo Projekt.

Update
- HTTP Api ActiveX hinzugefügt vs "COM nicht initialisiert" Fehler
- Zeitmessung inkl. Auswertung, momentan werden 4 Zeilen angezeigt, die ungewollten rauskommentieren/löschen
- simple Benchmark-Konfiguration hinzugefügt
- ClassNames verteilt

Delphi-Quellcode:
unit uMain;

interface

uses
  Winapi.Windows, Vcl.Controls, Vcl.StdCtrls, Vcl.Dialogs, System.Classes,
  Vcl.ExtCtrls, Vcl.Forms, System.SysUtils, System.Diagnostics;

type
  TFormMain = class(TForm)
    PanelTop: TPanel;
    PanelClient: TPanel;
    Memo1: TMemo;
    EditURL: TEdit;
    ButtonDownload: TButton;
    ButtonSaveOriginal: TButton;
    FileSaveDialog1: TFileSaveDialog;
    ButtonSaveMemo: TButton;
    ComboBoxApi: TComboBox;
    PanelBenchmark: TPanel;
    CheckBoxBenchmark: TCheckBox;
    GroupBoxBenchConfig: TGroupBox;
    ComboBoxBitsBytes: TComboBox;
    ComboBoxByteCalc: TComboBox;
    procedure ButtonDownloadClick(Sender: TObject);
    procedure ButtonSaveOriginalClick(Sender: TObject);
    procedure ButtonSaveMemoClick(Sender: TObject);
    procedure CheckBoxBenchmarkClick(Sender: TObject);
  private
    { Private declarations }
    DataString: String;
    Function GetWinInet ( Const xURL : String ) : UTF8String;
    Function GetHttpApi ( Const xURL : String ) : String;
    Function GetTDownloadURL ( Const xURL : String ) : String;
    function GetTHTTPClient ( Const xURL : String ) : String;
  public
    { Public declarations }
  end;

var
  FormMain: TFormMain;

implementation

Uses
  WinApi.WinInet,
  System.Variants, WinApi.ActiveX, System.Win.ComObj,
  Vcl.ExtActns,
  System.Net.HttpClient
  ;

{$R *.dfm}

function TFormMain.GetWinInet ( Const xURL : String ) : UTF8String;
var
  NetHandle: HINTERNET;
  UrlHandle: HINTERNET;
  Buffer: array[0..1023] of byte;
  BytesRead: dWord;
  StrBuffer: UTF8String;
begin
  Result := '';
  NetHandle := InternetOpen('Delphi-PRAXiS RockZ', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if Assigned(NetHandle) then
    try
      UrlHandle := InternetOpenUrl(NetHandle, PChar(xURL), nil, 0, INTERNET_FLAG_RELOAD, 0);
      if Assigned(UrlHandle) then
        try
          repeat
            InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesRead);
            SetString(StrBuffer, PAnsiChar(@Buffer[0]), BytesRead);
            Result := Result + StrBuffer;
          until BytesRead = 0;
        finally
          InternetCloseHandle(UrlHandle);
        end
      else
        raise Exception.CreateFmt('Cannot open URL %s', [xURL]);
    finally
      InternetCloseHandle(NetHandle);
    end
  else
    raise Exception.Create('Unable to initialize Wininet');
end;

Function TFormMain.GetHttpApi ( Const xURL : String ) : String;
var
  HTTP: OleVariant;
begin
  Result := '';
  CoInitialize(nil);
  try
    HTTP := CreateOleObject('WinHttp.WinHttpRequest.5.1');
    HTTP.Open('GET', xURL, False);
    HTTP.Send;
    Result := HTTP.ResponseText;
  finally
    HTTP := Unassigned;
    CoUninitialize;
  end;
end;

Function TFormMain.GetTDownloadURL ( Const xURL : String ) : String;
var
  dl: TDownloadURL;
  iFileHandle: Integer;
  iFileLength: Integer;
  iBytesRead: Integer;
  Buffer: PAnsiChar;
  i: Integer;
begin
  Result := '';
  if FileSaveDialog1.Execute then
  begin
    dl := TDownloadURL.Create(Self);
    try
      dl.URL := xURL;
      dl.FileName := FileSaveDialog1.FileName;
      dl.ExecuteTarget(nil);
    finally
      dl.Free;
      try
        iFileHandle := System.SysUtils.FileOpen(FileSaveDialog1.FileName, fmOpenRead);
        iFileLength := System.SysUtils.FileSeek(iFileHandle,0,2);
        System.SysUtils.FileSeek(iFileHandle,0,0);
        Buffer := System.AllocMem(iFileLength + 1);
        iBytesRead := System.SysUtils.FileRead(iFileHandle, Buffer^, iFileLength);
        Result := Buffer;
      finally
        System.SysUtils.FileClose(iFileHandle);
        System.FreeMem(Buffer);
      end;
    end;
  end;
end;

function TFormMain.GetTHTTPClient ( Const xURL : String ) : String;
var
  HttpClient: THttpClient;
  HttpResponse: IHttpResponse;
begin
  Result := '';
  HttpClient := THTTPClient.Create;
  try
    HttpResponse := HttpClient.Get( xURL );
    Result := HttpResponse.ContentAsString();
  finally
    HttpClient.Free;
  end;
end;

procedure TFormMain.ButtonDownloadClick(Sender: TObject);
var
  temp1, temp2: String;
  i : Integer;
  Watch: TStopWatch;
begin
  Memo1.Clear;
  ButtonDownload.Enabled := False;
  ButtonSaveOriginal.Enabled := False;
  ButtonSaveMemo.Enabled := False;
  PanelBenchmark.Enabled := False;
  Temp1 := EditURL.Text; Temp2 := ''; DataString := '';
  Memo1.Refresh;
  Memo1.Lines.Add('Downloading Data from ' +Temp1);
  Memo1.Lines.Add('Please Wait...');
  if CheckBoxBenchmark.Checked then
  begin
    Watch := TStopWatch.Create();
    Watch.Start;
  end;
  if Length(Temp1) > 0 then
   case ComboBoxApi.ItemIndex of
    0: DataString := GetWinInet( Temp1 );
    1: DataString := GetHttpApi( Temp1 );
    2: DataString := GetTDownloadURL( Temp1 );
    3: DataString := GetTHTTPClient( Temp1 );
   end;
  if CheckBoxBenchmark.Checked then Watch.Stop;
  if Length(DataString) > 0 then
  begin
    Memo1.Lines.Text := DataString;
    i := Length(Memo1.Lines.Text) ;
    Memo1.Lines.Add('');
    Memo1.Lines.Add('HTTP/S HTML Source from: '+Temp1);
    if Length(DataString)-i < 0 then temp2 := 'Additional added '+IntToStr(i-Length(DataString))+' extra Unicode bytes.';
    if Length(DataString)-i = 0 then temp2 := 'Plain Ascii detected.';
    if Length(DataString)-i > 0 then temp2 := 'Warning! '+IntToStr(Length(DataString)-i)+' bytes missing in Display!';
    Memo1.Lines.Add('Downloaded: '+IntToStr(Length(DataString)) +' bytes, displaying: ' +IntToStr(i)+ ' chars. '+temp2);
    if CheckBoxBenchmark.Checked then
    begin
      if (((ComboBoxBitsBytes.ItemIndex = 0)or(ComboBoxBitsBytes.ItemIndex = 1))and((ComboBoxByteCalc.ItemIndex = 0) or (ComboBoxByteCalc.ItemIndex = 1))) then
        Memo1.Lines.Add('Downloaded needed '+IntToStr(Watch.ElapsedMilliseconds)+' ms, that is '+FloatToStrF(Length(DataString) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' bytes/second <-> '+FloatToStrF((Length(DataString) / 1024) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' kbyte/s <-> '+FloatToStrF((Length(DataString) / 1024 / 1024) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' mbyte/s.');
      if (((ComboBoxBitsBytes.ItemIndex = 0)or(ComboBoxBitsBytes.ItemIndex = 2))and((ComboBoxByteCalc.ItemIndex = 0) or (ComboBoxByteCalc.ItemIndex = 1))) then
        Memo1.Lines.Add('Downloaded needed '+IntToStr(Watch.ElapsedMilliseconds)+' ms, that is '+FloatToStrF((Length(DataString)*8) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' bits/second <-> '+FloatToStrF(((Length(DataString)*8) / 1024) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' kbit/s <-> '+FloatToStrF(((Length(DataString)*8) / 1024 / 1024) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' mbit/s.');
      if (((ComboBoxBitsBytes.ItemIndex = 0)or(ComboBoxBitsBytes.ItemIndex = 1))and((ComboBoxByteCalc.ItemIndex = 0) or (ComboBoxByteCalc.ItemIndex = 2))) then
        Memo1.Lines.Add('Downloaded needed '+IntToStr(Watch.ElapsedMilliseconds)+' ms, that is '+FloatToStrF(Length(DataString) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' bytes/second <-> '+FloatToStrF((Length(DataString) / 1000) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' kbyte/s <-> '+FloatToStrF((Length(DataString) / 1000 / 1000) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' mbyte/s.');
      if (((ComboBoxBitsBytes.ItemIndex = 0)or(ComboBoxBitsBytes.ItemIndex = 2))and((ComboBoxByteCalc.ItemIndex = 0) or (ComboBoxByteCalc.ItemIndex = 2))) then
      Memo1.Lines.Add('Downloaded needed '+IntToStr(Watch.ElapsedMilliseconds)+' ms, that is '+FloatToStrF((Length(DataString)*8) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' bits/second <-> '+FloatToStrF(((Length(DataString)*8) / 1000) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' kbit/s <-> '+FloatToStrF(((Length(DataString)*8) / 1000 / 1000) / (Watch.ElapsedMilliseconds / 1000), ffFixed, 35, 2)+' mbit/s.');
{
      Memo1.Lines.Add('Above calculations based on 1024 byte = 1 kb for your pleasure 1000 byte = 1 kb follows.');
      }

    end;
    ButtonSaveOriginal.Enabled := True;
    ButtonSaveMemo.Enabled := True;
  end;
  PanelBenchmark.Enabled := True;
  ButtonDownload.Enabled := True;
end;

procedure TFormMain.ButtonSaveOriginalClick(Sender: TObject);
var
 FS: TFileStream;
 xBuf: TBytes;
 i: Integer;
begin
 if FileSaveDialog1.Execute then
 begin
   SetLength(xBuf, Length(DataString)-1);
   for i := 1 to Length(DataString) do
    xBuf[i-1] := Ord(DataString[i]);
   FS := TFileStream.Create(FileSaveDialog1.FileName, fmCreate);
   FS.WriteBuffer(xBuf, 0, Length(DataString));
   FS.Free;
 end;
end;

procedure TFormMain.ButtonSaveMemoClick(Sender: TObject);
begin
 if FileSaveDialog1.Execute then
 begin
   Memo1.Lines.SaveToFile(FileSaveDialog1.FileName);
 end;
end;

procedure TFormMain.CheckBoxBenchmarkClick(Sender: TObject);
begin
 GroupBoxBenchConfig.Enabled := CheckBoxBenchmark.Checked;
end;

end.
Angehängte Dateien
Dateityp: 7z Internet Download.7z (4,4 KB, 14x aufgerufen)
Gruß vom KodeZwerg

Geändert von KodeZwerg (30. Apr 2018 um 10:29 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Internet Downloads verschiedene Get() Varianten

  Alt 29. Apr 2018, 23:22
Neue Version, siehe Post #1
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Internet Downloads verschiedene Get() Varianten

  Alt 30. Apr 2018, 10:30
Micro-Update in Post #1
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Daniel
(Co-Admin)

Registriert seit: 30. Mai 2002
Ort: Hamburg
13.919 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Internet Downloads verschiedene Get() Varianten

  Alt 30. Apr 2018, 10:37
Das mag für Dich ein interessantes Forschungs-Feld sein.
Aber läufst Du nicht in die falsche Richtung? Du lässt Dir den Datenstrom vom Server per String geben - wäre es nicht besser, das, was man bekommt, zuerst als Byte-Strom zu begreifen, dann etwaige Meta-Daten wie "Content-Encoding" und Konsorten auszuwerten, um am Ende einen korrekt codierten String (oder ein PNG oder ein ZIP-Archiv oder was auch immer) daraus zu erstellen?
Auch das Thema "Threading" vermisse ich ein wenig. Auf die Geschwindigkeit, in der Dir die Daten geliefert werden, hast Du i.A. keinen Einfluss. Erledigst Du den Download also im Main-Thread, steht halt erstmal Deine gesamte Anwendung.
Was zudem fehlt, ist eine Abgrenzung der verschiedenen Methoden. Warum sollte ich ein ActiveX-Objekt bemühen, wenn ich mit den NetHTTP-Komponenten oder den INDYs arbeiten könnte?
Daniel R. Wolf
mit Grüßen aus Hamburg
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.540 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Internet Downloads verschiedene Get() Varianten

  Alt 30. Apr 2018, 10:58
Und gehört das wirklich in diese Sparte? Es handelt sich ja nicht um ein konkretes Problem.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Internet Downloads verschiedene Get() Varianten

  Alt 30. Apr 2018, 11:00
Das mag für Dich ein interessantes Forschungs-Feld sein.
In der Tat, neue Sachen zu Entdecken macht Spass!
Du lässt Dir den Datenstrom vom Server per String geben - wäre es nicht besser, das, was man bekommt, zuerst als Byte-Strom zu begreifen
Ich bin für Verbesserungen jederzeit bereit. Meine Binär-Tests waren erfolgreich (beim speichern wird es ein Byte-Strom).
Auch das Thema "Threading" vermisse ich ein wenig. Auf die Geschwindigkeit, in der Dir die Daten geliefert werden, hast Du i.A. keinen Einfluss. Erledigst Du den Download also im Main-Thread, steht halt erstmal Deine gesamte Anwendung.
Das ist leider wahr. Ich könnte die Get() Sachen auch als Thread starten nur sehe ich darin noch keinen Unterschied für dieses Beispiel-Projekt.
Was zudem fehlt, ist eine Abgrenzung der verschiedenen Methoden.
Da helf mir mal bitte auf die Sprünge, es ist doch jede Variante einzeln abgekapselt?
Warum sollte ich ein ActiveX-Objekt bemühen, wenn ich mit den NetHTTP-Komponenten oder den INDYs arbeiten könnte?
Weil ich in diesem Beispiel auf andere Methoden eingehen wollte. Nur die HTML Api braucht das ActiveX.
Zugegeben meine ersten Gehversuche fanden auch mit Indy statt aber da war ich zu doof es bei Laufzeit mit SSL hinzubekommen.
Ziel dieses Beispiels soll sein das man keine Komponenten braucht die alle erst konfiguriert werden müssen bevor man in der Lage ist eine Datei oder HTML Quelltext zu laden.

Und bezüglich Content, dargestellt werden soll/kann nur "Text", halt HTML Source, runtergeladen werden kann vieles.

Und gehört das wirklich in diese Sparte? Es handelt sich ja nicht um ein konkretes Problem.
In CodeLib kann ich nichts Erstellen.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
1.017 Beiträge
 
Delphi 2009 Professional
 
#7

AW: Internet Downloads verschiedene Get() Varianten

  Alt 30. Apr 2018, 11:33
Ich find's gut, weil's die EXE nicht unnötig aufbläht, und insbesondere bei HTTPS keine Zusatzkomponenten braucht. Derzeit verwende ich dafür TDownloadURL, was bei einfachen GET-Requests geht, aber aber POST-Requests versagt.

Du könntest noch zu den einzelnen Methoden folgende Informationen erwähnen, falls du sie herausfinden kannst:
* Wie gut funktionieren sie mit POST?
* Wie gut lässt sich der Header bearbeiten? Ich benötige beispielsweise einen sehr seltsamen Request-Header.
* Seit wann geht das? TDownloadURL geht sein Jahrmillionen, das ist klar, aber seit wann geht der Rest?

Und gehört das wirklich in diese Sparte? Es handelt sich ja nicht um ein konkretes Problem.
In CodeLib kann ich nichts Erstellen.
Das ist eine eigene Funktion. Die Einträge sollen dann eingeordnet werden, aber der Bereich wird seit 5 Jahren nicht mehr moderiert, von daher...
Janni
2005 PE, 2009 PA, XE2 PA
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Internet Downloads verschiedene Get() Varianten

  Alt 30. Apr 2018, 12:19
* Seit wann geht das?
WinInet = WinInet.dll = gibt es seit InternetExplorer 3 und nimmt sich dessen Settings
HttpApi = Winhttp.dll = ab Windows XP / Windows 2000 mit SP3 - benötigt ActiveX, im Quelltext enthalten
TDownLoadURL = TDownLoadURL
THTTPClient = THTTPClient
* Wie gut funktionieren sie mit POST?
Für Deine Zwecke sollte der THTTPClient alles bieten was Du brauchst.
Gruß vom KodeZwerg

Geändert von KodeZwerg (30. Apr 2018 um 12:57 Uhr) Grund: ActiveX Bemerkung hinzugefügt.
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Internet Downloads verschiedene Get() Varianten

  Alt 1. Mai 2018, 18:08
ot
Im Anhang sind zwei Dateien, einmal das Original, da würde mich Interessieren ob es auch tatsächlich so ist, könntest Du das Überprüfen?
Die Memo.html ist einfach nur eine Memo-Kopie, ich glaub ich muss da auch noch Hand anlegen, in Memo-Anzeige sieht alles gut aus aber wenn ich Kopie von Memo in Editor lade sehen die Unicode Zeichen strange aus, wenn ich Original.html lade passt alles also muss es an der Art liegen wie Memo speichert, mit/ohne Codierung obwohl der mir "Plain Ascii" anzeigt, also genauso viele Bytes die reingekommen sind werden dargestellt ohne Zusätzliche Unicode bytes, wie Du merkst blicke ich selbst da noch nicht so ganz durch.
Es funktioniert bei mir nur mit THTTPClient. Der WinInet haut einen 400er Fehler raus und die Http Api einen 404er
TDownLoadURL versuche ich nach Möglichkeit auszuweichen weil der immer eine Datei anlegen will, da muss ich erst noch forschen ob ich das umgehen kann.
Anhang nur für Dich, wenn geladen sag Bescheid und ich lösche es wieder, Danke.
/ot
Angehängte Dateien
Dateityp: 7z blacklist2.7z (16,2 KB, 5x aufgerufen)
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:13 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz