AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Klasse: HTTPDownloader...
Thema durchsuchen
Ansicht
Themen-Optionen

Klasse: HTTPDownloader...

Ein Thema von Real-TTX · begonnen am 29. Apr 2009 · letzter Beitrag vom 1. Mai 2009
Antwort Antwort
Seite 1 von 2  1 2      
Real-TTX
Registriert seit: 7. Mai 2008
... leider nur ein Aufsatz für die Indy Komponente.

Es ist meine erste Klasse in Delphi. Ich bitte dass ihr wenn ihr Lust habt mal drüber schaut und vllt ein paar Verbesserungs Tipps geben könntet
Und daher bitte ich gerade auf Styleguide zu achten. Ich an den meisten Stellen(bis auf 2) auch die 80 Zeichen marke eingehalten. An 2 Stellen muss ich noch eine gute Formatierung suchen...

http://pastebin.ca/1407680

Delphi-Quellcode:
unit HTTPDownloader;

interface

uses
  SysUtils,
  StrUtils,
  Dialogs,
  Classes,
  Forms,
  IdBaseComponent,
  IdComponent,
  IdTCPConnection,
  IdTCPClient,
  IdAuthentication,
  IdHTTP;

type

  TUpdateRate = (urFast, urNormal, urSlow);

  TDownload = record
    ID : integer;
    Count : integer;
    URL : array[0..3] of string;
    Size : int64;
    SizeFormated : string;
    Downloaded : int64;
    DownloadedFormated : string;
    DownloadedPercent : integer;
  end;

  TDownloadWork = procedure(Download : TDownload) of object;
  TDownloadBegin = procedure(Download : TDownload) of object;
  TDownloadEnd = procedure(Download : TDownload) of object;

  THTTPDownloader = class
  private
    // Variablen
    bolAppProcessMsg: boolean;
    intDownloads : integer;
    urUpdateRate : TUpdateRate;
    arrDownloadList : array of array[0..1] of string;
    objHTTP : TidHTTP;
    CurrentDownload : TDownload;
    // Ereignisse
    DownloadWork : TDownloadWork;
    DownloadBegin : TDownloadBegin;
    DownloadEnd : TDownloadEnd;
    // Funktionen
    procedure DownloadOnWork(ASender: TObject;
                             AWorkMode: TWorkMode;
                             AWorkCount: Int64);
    procedure ClearCurrentDownload;
    function GetSizeName(const Size : int64): String;
  public
    // Constructor / Destructor
    constructor Create;
    destructor Destroy; override;
    // Funktionen / Prozeduren
    function GetURLFileSize(aURL : string) : int64;
    function Download(aURL : string; aDest : string) : boolean;
    procedure ItemsDownload;
    procedure ItemsAdd(aURL : string; aDest : string);
    procedure ItemsClear;
    // Eigenschaften
    property UpdateRate : TUpdateRate
                              read urUpdateRate
                              write urUpdateRate;
    property ProcessMessages : boolean
                              read bolAppProcessMsg
                              write bolAppProcessMsg;
    property Downloads : integer read intDownloads;
    property PercentCurrent : integer read intDownloads;
    property PercentAll : integer read intDownloads;
    // Ereignisse
    property OnDownloadWork : TDownloadWork
                          read DownloadWork
                          write DownloadWork;
    property OnDownloadBegin: TDownloadBegin
                          read DownloadBegin
                          write DownloadBegin;
    property OnDownloadEnd : TDownloadEnd
                          read DownloadEnd
                          write DownloadEnd;

  end;

var
    Downloader : THTTPDownloader;

implementation

// =============================================================================
// Public
// =============================================================================

constructor THTTPDownloader.Create;
begin
  inherited;
  // HTTP Objekt (Indy) erzeugen und Eigenschaften setzen
  objHTTP := TidHTTP.Create(nil);
  objHTTP.AllowCookies := true;
  objHTTP.RedirectMaximum := 10;
  // HTTP Objekt Ereigniss zuweißen
  objHTTP.OnWork := DownloadOnWork;
  // Variablen Initialisieren
  intDownloads := 0;
  SetLength(arrDownloadList,0);
end;

destructor THTTPDownloader.Destroy;
begin
  inherited;
  // Aufräumen
  objHTTP.Destroy;
end;

procedure THTTPDownloader.ItemsAdd(aURL : string; aDest : string);
begin
  // DownloadList-Array um eins erhöhen
  SetLength(arrDownloadList,Length(arrDownloadList)+1);
  // 2te Dimension des Arrays befüllen
  arrDownloadList[Length(arrDownloadList)-1,0] := aURL;
  arrDownloadList[Length(arrDownloadList)-1,1] := aDest;
  // Download Property Var. um 1 erhöhen und Record zuweisen
  inc(intDownloads);
  CurrentDownload.Count := intDownloads;
end;

procedure THTTPDownloader.ItemsClear;
begin
  // DownloadList-Array auf 0 Setzen
  SetLength(arrDownloadList, 0);
  // Download Property Var. auf 0 setzen und Record zuweißen
  intDownloads := 0;
  CurrentDownload.Count := 0;
end;

procedure THTTPDownloader.ItemsDownload;
var
  i: Integer;
begin
  // Jedes Element des DownloadList-Arrays durchlaufen und Datei herunterladen
  for i := 0 to Length(arrDownloadList) - 1 do
  begin
    CurrentDownload.ID := i + 1;
    Self.Download(arrDownloadList[i,0],arrDownloadList[i,1]);
  end;
end;

function THTTPDownloader.Download(aURL : string; aDest : string) : boolean;
var
  DownloadStream : TMemoryStream;
begin
  // Standartrückgabewert setzen (wird bei Fehlerfall geändert)
  result := true;
  // Stream erzeugen
  DownloadStream := TMemoryStream.Create;
  DownloadStream.Clear;
  // Versuche Datei herunterzulasen und abzuspeichern
  try
    // Header Informationen abfragen
    objHTTP.Head(aURL);
    // ProcessMessages falls Property gesetzt
    if bolAppProcessMsg then
      Application.ProcessMessages;
    // RECORD befüllen
    CurrentDownload.Size := objHTTP.Response.ContentLength;
    CurrentDownload.SizeFormated := Self.GetSizeName(objHTTP.Response.ContentLength);
    CurrentDownload.URL[0] := aURL;
    CurrentDownload.URL[1] := copy(
                                    copy(aURL, 8, length(aURL)),
                                    0,
                                    Pos('/', copy(
                                                  aURL,
                                                  8
                                                  ,
                                                  length(aURL)
                                                  )
                                        )-1
                                    );
    CurrentDownload.URL[2] := copy(
                                    aURL,
                                    length(aURL) - (
                                                    Pos(
                                                        '/',
                                                        AnsiReverseString(aURL)
                                                        )-1
                                                    ) + 1,
                                    length(aURL)
                                  );
    // Ereigniss : DownloadBegin aufrufen - falls definiert
    if @DownloadBegin <> nil then
      DownloadBegin(CurrentDownload);
    // ProcessMessages falls Property gesetzt
    if bolAppProcessMsg then
      Application.ProcessMessages;
    // Download in Stream laden
    objHTTP.Get(aURL, DownloadStream);
    // Ereigniss : DownloadEnd aufrufen - falls definiert
    if @DownloadEnd <> nil then
      DownloadEnd(CurrentDownload);
    // ProcessMessages falls Property gesetzt
    if bolAppProcessMsg then
      Application.ProcessMessages;
    // Stream als Datei speichern
    DownloadStream.SaveToFile(aDest);
  except
    // Rückgabewert setzen - Fehler ist aufgetreten
    result := false;
  end;
  // Aufräumen
  DownloadStream.Free;
  //Self.ClearCurrentDownload;
end;

function THTTPDownloader.GetURLFileSize(aURL : string) : int64;
begin
  // Versuche Header Informationen abzufragen
  try
    // Ermittle HeadderInformationen
    objHTTP.Head(aURL);
    // ProcessMessages falls Property gesetzt
    if bolAppProcessMsg then
      Application.ProcessMessages;
    // Lese HeaderInformationen in Rückgabewert
    result := objHTTP.Response.ContentLength;
  except
    // Falls ein Fehler auftritt, ist der Rückgabewert -1
    result := -1;
  end;
end;


// =============================================================================
// Private
// =============================================================================

procedure THTTPDownloader.ClearCurrentDownload;
begin
    // Record auf Standartwerte zurücksetzen
    CurrentDownload.Size := 0;
    CurrentDownload.SizeFormated := '';
    CurrentDownload.ID := 0;
    CurrentDownload.Count := 0;
    CurrentDownload.Downloaded := 0;
    CurrentDownload.DownloadedFormated := '';
    CurrentDownload.DownloadedPercent := 0;
    CurrentDownload.URL[0] := '';
    CurrentDownload.URL[1] := '';
    CurrentDownload.URL[2] := '';
end;

procedure THTTPDownloader.DownloadOnWork(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
var
  intRate : integer;
begin
    // Standartwer falls Property nicht gesetzt = 2, urNormal
    intRate := 2;
    // urUpdateRate auswählen
    case urUpdateRate of
      urFast : begin intRate := 1; end;
      urNormal : begin intRate := 2; end;
      urSlow : begin intRate := 3; end;
    end;
    // Funktion verlassen falls Rate nicht zutrifft und AWorkCount == CurrentDownload.Size
    if (not(AWorkCount = CurrentDownload.Size)) and
       ((AWorkCount mod intRate) <> 0) then exit;
     // Ereigniss : DownloadWork aufrufen - falls definiert
    if @DownloadWork <> nil then
    begin
      // Record.Downloaded setzen
      CurrentDownload.Downloaded := AWorkCount;
      CurrentDownload.DownloadedPercent := round((AWorkCount / CurrentDownload.Size) * 100);
      CurrentDownload.DownloadedFormated := Self.GetSizeName(AWorkCount);
      // Ereigniss DownloadWork
      DownloadWork(CurrentDownload);
      // ProcessMessages falls Property gesetzt
      if bolAppProcessMsg then
        Application.ProcessMessages;
    end;
end;

function THTTPDownloader.GetSizeName(const Size : int64): String;
begin
  Result := 'Error';
  if Size = -1 then exit;
  if Size < 1024 then
  begin
    Result := inttostr(Size)+' Byte';
    exit;
  end;
  if (1024 <= Size) and (Size < 1048576) then
  begin
    Result := floattostr((round((Size/1024)*100))/100)+' KB';
    exit;
  end;
  if (1048576 <= Size) and (Size < 1099511627776) then
  begin
    Result := floattostr((round((Size/1048576)*100))/100)+' MB';
    exit;
  end;
  if Size > 1099511627776 then
  begin
    Result := floattostr((round((Size/1099511627776)*100))/100)+' GB';
  end;
end;



end.

Gruß, Real-TTX
 
Benutzerbild von Mithrandir
Mithrandir
 
#2
  Alt 29. Apr 2009, 20:30
Besser wäre es, den Code entweder hier in [ delphi ][ /delphi ] - Tags einzufügen, oder in eine Unit zu packen und in Anhang verfrachten.
米斯蘭迪爾
  Mit Zitat antworten Zitat
Benutzerbild von jfheins
jfheins
 
#3
  Alt 29. Apr 2009, 20:35
Ich hab jetzt nur mal kurz über die Formatierung geguckt ... und etwas ist mir ins Auge gestochen:

Sowas finde ich sehr unleserlich ...
Delphi-Quellcode:
    CurrentDownload.URL[1] := copy(
                                    copy(aURL, 8, length(aURL)),
                                    0,
                                    Pos('/', copy(
                                                  aURL,
                                                  8
                                                  ,
                                                  length(aURL)
                                                  )
                                        )-1
                                    );
    CurrentDownload.URL[2] := copy(
                                    aURL,
                                    length(aURL) - (
                                                    Pos(
                                                        '/',
                                                        AnsiReverseString(aURL)
                                                        )-1
                                                    ) + 1,
                                    length(aURL)
                                  );
Jeder Parameter auf einer neuen Zeileund einmal sogar das Komma extra

Soooo schlimm isses imho auch nicht, wenn man mal über 80 Zeichen kommt
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#4
  Alt 29. Apr 2009, 21:19
Delphi-Quellcode:
if @DownloadBegin <> nil then
  DownloadBegin(CurrentDownload);

if @DownloadEnd <> nil then
  DownloadEnd(CurrentDownload);

if @DownloadWork <> nil then
  begin
dieses ist immer <> nil, denn die Variablen sind immer vorhanden
Delphi-Quellcode:
if Assigned(DownloadBegin) then
  DownloadBegin(CurrentDownload);

if Assigned(DownloadEnd) then
  DownloadEnd(CurrentDownload);

if Assigned(DownloadWork) then
  begin

// und wenn schon NIL, dann eher so
if Pointer(DownloadBegin) <> nil then
  DownloadBegin(CurrentDownload);


Delphi-Quellcode:
// Standartwer falls Property nicht gesetzt = 2, urNormal
intRate := 2;
// urUpdateRate auswählen
case urUpdateRate of
  urFast : begin intRate := 1; end;
  urNormal : begin intRate := 2; end;
  urSlow : begin intRate := 3; end;
end;
schonmal etwas vom ELSE gehört und wozu die Begin-End?
Delphi-Quellcode:
// urUpdateRate auswählen
case urUpdateRate of
  urFast : intRate := 1;
  urSlow : intRate := 3;
  else intRate := 2;
end;

mit ein paar ELSE könne man einige Vergleiche eh weglassen, samt der "unnötigen" Exit.
ja meinst du, daß über 1 Terrabyte wirklich nötig sind?
PS: laut berechnung ist dein GB ein TB und GBhast du ganz vergessen
(1.099.511.627.776 = 1 TB)
Delphi-Quellcode:
function THTTPDownloader.GetSizeName(const Size : int64): String;
begin
  if Size > 1073741824 then
    Result := floattostr(trunc(Size/1073741824*100)/100)+' GB'
  else if Size > 1048576 then
    Result := floattostr(trunc(Size/1048576*100)/100)+' MB'
  else if Size > 1024 then
    Result := floattostr(trunc(Size/1024*100)/100)+' KB'
  else if Size >= 0 then
    Result := inttostr(Size)+' Byte'
  else
    Result := 'Error';
end;
.......




PS: von da drüben läßt sich dein Code nicht nutzen ... beim Rauskopieren wird da je Zeile eine Zeile mit 'nem # eingefügt ... voll unpraktisch
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
 
#5
  Alt 29. Apr 2009, 21:21
Zitat von himitsu:
PS: von da drüben läßt sich dein Code nicht nutzen ... beim Rauskopieren wird da je Zeile eine Zeile mit 'nem # eingefügt ... voll unpraktisch
Wohl dem, der den Download Raw Button entdeckt hat...
米斯蘭迪爾
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#6
  Alt 29. Apr 2009, 21:41
Zitat von Daniel G:
Wohl dem, der den Download Raw Button entdeckt hat...
jetzt wo du es sagst, hab aber dennoch ewig danach suchen müssen

Delphi-Quellcode:
TDownloadWork = procedure(Download : TDownload) of object;
TDownloadBegin = procedure(Download : TDownload) of object;
TDownloadEnd = procedure(Download : TDownload) of object;
wo die Definition doch gleich ist, mach doch einfach eine Definition raus.
TDownloadCallback = procedure(const Download : TDownload) of object; oder eventuell gleich nur eine CallbackProzedur für alles
Delphi-Quellcode:
TDownloadState = (dsBegin, dsWork, dsEnd);
TDownloadCallback = procedure(const Download : TDownload; State: TDownloadState) of object;
im Allgemeinem machen sich Const bei einigen anderen Prozeduren auch nicht schlecht (z.B. bei Int64- und String-Parametern)
Delphi-Quellcode:
function GetURLFileSize(const aURL : string) : int64;
function Download(const aURL, aDest : string) : boolean;
procedure ItemsAdd(const aURL, aDest : string);
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
 
#7
  Alt 29. Apr 2009, 22:10
Zitat von himitsu:
im Allgemeinem machen sich Const bei einigen anderen Prozeduren auch nicht schlecht (z.B. bei Int64- und String-Parametern)
Jetzt muss ich mal ganz blöd fragen:

Warum?
米斯蘭迪爾
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#8
  Alt 29. Apr 2009, 22:27
wenn die Variablen eh nicht verändert werden sollen, wozu sie veränderbar machen?
(also Prozedurintern)

gut, bei Strings gibt es die Referenzzählung, aber nicht immer (vorallem nicht bei WideString)
und bei Records und auch allem über 32 Bit wird ohne das Const erst eine Kopie des Parameters angelegt, worin die Prozeduinternen änderungen stattfinden können.

übergib mal z.B. ein rießiges Static-Array, einen großen Record oder einen langen WideString ... diese müssen erst kopiert und am Ende wieder freigegeben werden.
und auch bei kleinen Strukturen müßte das erst von Delphi gemacht werden, selbst wenn es unnötig wäre.

CONST (könnte man auch als IN), VAR, OUT und (nichts) gibt es ja nicht umsonst zur Auswahl
und Const bzw. Var wird bei "größeren" Strukturen dann einfach als Zeiger auf die Originaldaten umgesetzt und läuft nicht über 'ne "Kopie".
(kleine Ausnahmen bilden Objekte, welche "nur" Zeiger sind,
sowie Strings bzw. DynArrays, welche eine Referenzzählung besitzen)
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
 
#9
  Alt 29. Apr 2009, 22:42
Ah, ok, wieder was gelernt. Danke.
米斯蘭迪爾
  Mit Zitat antworten Zitat
Real-TTX

 
Delphi 2007 Enterprise
 
#10
  Alt 29. Apr 2009, 23:34
Soviel, kann ich jetzt auf die schnelle nicht verarbeiten :O

Aber danke für die Tipps.
Das mit den Konstanten bei Funktinen ist wirklich sehr hübsch.



Zitat von himitsu:
Delphi-Quellcode:
TDownloadWork = procedure(Download : TDownload) of object;
TDownloadBegin = procedure(Download : TDownload) of object;
TDownloadEnd = procedure(Download : TDownload) of object;
oder eventuell gleich nur eine CallbackProzedur für alles
Delphi-Quellcode:
TDownloadState = (dsBegin, dsWork, dsEnd);
TDownloadCallback = procedure(const Download : TDownload; State: TDownloadState) of object;
wo die Definition doch gleich ist, mach doch einfach eine Definition raus.
TDownloadCallback = procedure(const Download : TDownload) of object;
... Danke

PS: Die Funktion GetSizeName habe ich selbst nur hier aus dem Forum gestohlen

bei der Mehrfachverzweigung habe ich Begin End genommen weil es ohne nicht ging?
Und muss man da nicht normalerweise auch break benutzen, da es nur dumme DOS Sprungmarken sind ?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 08: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