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 2 von 2     12   
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 himitsu
himitsu
Online

 
Delphi 12 Athens
 
#11
  Alt 30. Apr 2009, 00:02
in C sind es nur Sprungmarken, aber in Delphi wird da automatisch rausgesprungen ... ist eher mit mehreren IFs vergleichbar.


Delphi-Quellcode:
case x of
  1: begin
       a;
     end;
  2: begin
       b;
     end;
  3: begin
       c:
     end;
  else begin
         e;
       end;
end;

// entspricht (nur ohne mehrfachen vergleich)

if x = 1 then begin
  a;
end else if x = 2 then begin
  b;
end else if x = 3 then begin
  c;
end else begin
  e;
end;
  Mit Zitat antworten Zitat
shmia

 
Delphi 5 Professional
 
#12
  Alt 30. Apr 2009, 15:55
Wirf das Property ProcessMessages mal komplett aus der Klasse raus.
Wenn jemand seine Applikation mit Application.ProcessMessages am Leben erhalten möchte,
dann kann er das doch im Event OnDownloadWork tun.
Es ist je nach Kontext (VCL-Anwendung, Non-VCL-Anwendung, Konsolenanwendung) die Aufgabe des Benutzers der Klasse dies zu tun.
Damit kann man auch die Unit Forms aus dem Uses-Abschnitt entfernen.
Andreas
  Mit Zitat antworten Zitat
Real-TTX

 
Delphi 2007 Enterprise
 
#13
  Alt 30. Apr 2009, 19:48
k, jetzt wo du es sagst.. Ich nehms sofort raus. Ist ja peinlich

Danke & Gruß
Real-TTX
  Mit Zitat antworten Zitat
Apollonius

 
Turbo Delphi für Win32
 
#14
  Alt 30. Apr 2009, 19:57
Zitat von himitsu:
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);
Ein einfaches @ ermittelt den eigentlichen Wert des Methodenzeigers, erst @@ die Adresse. Das klingt seltsam, ist aber so. Insofern ist auch der ursprüngliche Code korrekt.

Insgesamt finde ich die Benennungskonventionen im Code etwas seltsam. Normalerweise erhält das hinter einem Property stehende Feld als Name einfach ein f und den Namen der Eigenschaft. Präfixe wie bol-, int- usw. halte ich für unpraktisch.
  Mit Zitat antworten Zitat
Namenloser

 
FreePascal / Lazarus
 
#15
  Alt 30. Apr 2009, 20:03
Zitat von Apollonius:
Insgesamt finde ich die Benennungskonventionen im Code etwas seltsam. Normalerweise erhält das hinter einem Property stehende Feld als Name einfach ein f und den Namen der Eigenschaft. Präfixe wie bol-, int- usw. halte ich für unpraktisch.
Zitat von Real-TTX:
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 ?
Er kommt von C
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
 
#16
  Alt 1. Mai 2009, 08:54
Zitat von NamenLozer:
Er kommt von C
Nee, von Perl...
米斯蘭迪爾
  Mit Zitat antworten Zitat
Real-TTX

 
Delphi 2007 Enterprise
 
#17
  Alt 1. Mai 2009, 09:25
Zitat von Apollonius:
Insgesamt finde ich die Benennungskonventionen im Code etwas seltsam. Normalerweise erhält das hinter einem Property stehende Feld als Name einfach ein f und den Namen der Eigenschaft. Präfixe wie bol-, int- usw. halte ich für unpraktisch.
Ich bin so eine Umfangreiche IDE noch nicht gewohnt Einfach mit der Maus über die Variable und schon sieht man von welchem Typ diese ist? Was ein unnötiger Luxus Darum auch die Bennenung. Als ich noch mit Perl/C gearbeitet habe: C in der Schule - Dort mussten wir einfach den Notepad von MS nutzen und Compiler & Linker selbst bedienen. Und Perl... Naja.. Gibts einfach keine IDE in der Art

Was für eine Bedeutung hätte der Präfix : "f" ?

Gruß, Real-TTX
  Mit Zitat antworten Zitat
mkinzler

 
Delphi 11 Alexandria
 
#18
  Alt 1. Mai 2009, 09:29
F steht für Field und wird für private Eigenschaften verwendet dazugehörige Properties dann ohen F

Delphi-Quellcode:
 TDemoKlasse = class
   private
     FName: string;
   published
     property Name: string read Fname write FName;
 end;
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

 
Delphi 12 Athens
 
#19
  Alt 1. Mai 2009, 11:33
Da gibt es so inofizielle Formatierungsregeln/-hinweise, damit die Quellcodes halbwegs gleich aufgebaut/formatiert sind und somit jeder in fremden Codes erstmal einen leichteren Einblick bekommen kann (da er schonmal weiß was wofür steht)

Wie z.B. viele den Funktionsparametern ein a vorranstellen, Klassen mit T und Interfaces mit I beginnen ......

OK, bei mir haben Felder z.B. ein _ vorranstehn, da ich es mir vor Jahren so angewöhnt hatte und ich es übersichtlicher find (das auch andere Dinge mal mit F anfangen können)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 00:42 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