TIdHTTP Partial Download(Parça Parça Download)

// 30 Mayıs 2009 // Delphi, Internet, Programlama

Hemen hemen hergün internetten birşeyler indirip duruyoruz. Kimi zaman çeşitli resim dosyaları, kimi zaman videolar kimi zamanda işimizle alakalı yada değil başka materyaller. Bu dosyaları bilgisayarımıza indirirken çoğu zaman indirme yönetici programlarından istifade ediyoruz. FlashGet, GetRight gibi. Bu programların indirilecek dosyayı bir kaç parça halinde indirme özellikleri olduğu gibi, herhangi bir bağlantı sorununda kaldıkları yerden devam edebilme gibi akıllı özellikleri var. Bizlerin onları tercih etmesindeki yegane neden de bu zaten. Peki hiç düşündünüz mü, internetten bir dosya bir kaç parça halinde nasıl indirilebiliyor ? Yada indirme işleminde sorun olduğunda kalınan yerden indirmeye nasıl devam edilebiliyor ?

Bir önceki makalemde BITS konusunu ele almıştım. BITS’de dosyalarımızı sessiz sedasız indirme yeteneğine sahipti. Aynı zamanda kaldığı yerden devam da edebiliyordu. Ancak arka planda ne gibi bir teknoloji kullandığı hakkında hiçbir fikrimiz yok. Nasıl yapıyor da internet üzerindeki bir dosyayı belirli bir yerinden okumaya başlayabiliyordu.. Aynı sorular diğer indirme yöneticileri için de sorulabilir elbette. İşte bu makalemizde bu konuya biraz ışık tutmaya çalışacağız. Ben sizlerle paylaşacağım örneğimde aşağıda göreceğiniz resim dosyasını bilgisayarıma indirmeye çalışacağım. Siz başka bir kaynak üzerindeki herhangi bir dosyayı deneyebilirsiniz. İşte indireceğimiz dosya ;)

turboman

İnternet üzerindeki herhangi bir dosyayı indirme işlemimizi Delphi ile birlikte gelen Indy kütüphanesinden faydalanarak yapacağız. Ben bu örneği Delphi 2009 üzerinde yazacağım. Daha önceki Delphi sürümlerinde Indy komut setlerinin değişik olabileceğini ancak ufak bir araştırma ile eski Delphi sürümlerine de adapte edilebileceğini düşünüyorum.

Bizim kullanacağımız bileşen TIdHttp aslında internet üzerinden herhangi bir veri kaynağını yerel bilgisayarınıza alabilmeniz için geliştirilmiş son derece güçlü bir bileşen. Biz bu bileşeni yukarıdaki resim dosyasını indirmek için kullanacağız. TIdHTTP bileşeninin makalemize konu olan parçalı indirme için Range gibi güçlü bir özelliği mevcut. Biz de bundan istifade edeceğiz. Ancak daha detay malümatlara girmeden evvel, indirmek istediğimiz dosyanın boyutunu öğrenebilmemiz gerekir. Boyutunu bilmediğimiz bir dosyayı istediğimiz sayıda parçaya da ayıramayız. Bunun için de yine TIdHttp’den yararlanacağız.

Örneğimiz, verilen bir internet adresindeki dosyayı lokalde belirttiğimiz bir yere belirttiğimiz isimde; istediğimiz kadar parçaya ayırarak indirecek. İndirme işlemini hız için TThread sınıfından istifade ederek gerçekleştirecek. Ancak örneğimiz, suspended download’ı desteklemiyor olacak. Yani indirmek için parçalara ayırdığımız thread’lerden birisinin hatalı sonlanması durumunda dosyamız düzgün bir şekilde indirilmemiş olacak. Lâkin vereceğimiz bilgiler ile, örneğimizi geliştirip indirilemeyen, yarım kalan parçaların indirilmesini sağlayabilecek kodları da pekâla yazabilirsiniz. Evet artık kodlarımıza başlamanın zamanı geldi sanırım:

  TRange = record
    StartPosition,
    EndPosition  : Integer;
  end;

  TDownloader = class;

  TDownloadThread = class(TThread)
  private
    fOwner : TDownloader;
    fUrl,
    fFileName : String;
    fRange : TRange;
  protected
    procedure Execute; override;
  public
    constructor Create(const AOwner : TDownloader; const AUrl, AFileName : String; ARange : TRange);
  end;

  TOnDownloadComplete = procedure(const FileName : String; const WorkTime : DWord) of object;
  TDownloader = class
  private
    fUrl,
    fFileName : String;
    fPart     : Integer;
    fWorkTime : DWord;
    Section   : TCriticalSection;

    fOnDownloadComplete : TOnDownloadComplete;

    procedure Notify;
  public
    constructor Create;
    destructor Destroy; override;

    procedure Download(const Url, FileName : String; const Part : Integer = 10);

    property OnDownloadComplete : TOnDownloadComplete read fOnDownloadComplete write fOnDownloadComplete;
  end;

Yukarıda gördüğünüz gibi indirme işlemleri için TRange isimli bir recordumuz, TDownloadThread ve TDownloader isimli birer sınıfımız mevcut. TDownloader sınıfının Download metodu Url parametresi ile aldığı internet üzerindeki bir dosyayı FileName parametresi ile belirttiğimiz isimle makinamıza indirecek. İndirme işlemi için ise TDownloadThread sınıfından istifade edecek. Part parametresi varsayılan olarak indirilecek dosyanın 10 parçada indirilmesini öngürüyor. Bu da 10 adet TDownloadThread nesnesi oluşturulacak ve çalıştırılacak demektir. TRange record’u bizim için hayati bir öneme sahip, lâkin henüz onu izah etmenin zamanı değil. Biz kodlarımıza devam edelim müsaadeniz ile;

{ TDownloader }

constructor TDownloader.Create;
begin
  inherited;

  Section := TCriticalSection.Create;
end;

destructor TDownloader.Destroy;
begin
  if Assigned(Section) then Section.Free;

  inherited;
end;

procedure TDownloader.Download(const Url, FileName: String;
  const Part: Integer);
var
  http : TIdHttp;
  Size : Int64;
  fs : TFileStream;
  sBuff : String;

  iCounter,
  iByteCount: Integer;
  Ranges : array of TRange;
begin
  fUrl := Url;
  fFileName := FileName + '.tmp';
  fPart := Part;

  http := TIdHttp.Create(nil);
  fs := TFileStream.Create(fFileName, fmCreate or fmShareDenyNone);
  try
    http.Head(url);
    Size := http.Response.ContentLength;
    if Size > 0 then
    begin
      SetLength(sBuff, Size);
      FillChar(Pointer(sBuff)^, Size, '0');
      fs.WriteBuffer(Pointer(sBuff)^, Size);
    end;
  finally
    fs.Free;
    http.Free;
  end;

  SetLength(Ranges, Part);
  iByteCount := Size div Part;

  Ranges[0].StartPosition := 0;
  Ranges[0].EndPosition   := iByteCount;

  for iCounter := 1 to Part - 1 do
  begin
    Ranges[iCounter].StartPosition  := (iCounter * iByteCount) + 1;
    Ranges[iCounter].EndPosition    := (iCounter + 1) * iByteCount;
  end;

  Ranges[Part-1].EndPosition := Size;

  fWorkTime := GetTickCount;
  for iCounter := Low(Ranges) to High(Ranges) do
  begin
    with TDownloadThread.Create(
                                Self,
                                fUrl,
                                fFileName,
                                Ranges[iCounter]
                               ) do Resume;
    Sleep(100);
  end;
end;

procedure TDownloader.Notify;
var
  NewFileName : String;
begin
  Section.Enter;
    Dec(fPart);
    if fPart = 0 then
    begin
      NewFileName := StringReplace(fFileName, '.tmp', '', [rfReplaceAll]);
      RenameFile(fFileName, NewFileName);

      if Assigned(fOnDownloadComplete) then
        fOnDownloadComplete(NewFileName, GetTickCount - fWorkTime);
    end;
  Section.Leave;
end;

TDownloader sınıfımızın constructor’unda TCriticalSection türünde bir nesne oluşturulduğunu görüyorsunuz. Bu nesne daha sonra Notify metodunun içerisinde kullanılmak üzere oluşturuluyor. TCriticalSection’lar genel olarak multi threaded programlamada kodunuzun kritik kısımlarına başka thread’lerin girmesine engel olmak adına mevcutturlar. TDownloader sınıfının Notify metodu, her TDownloadThread sınıfının bitişinde otomatikman çalıştırılacaktır. Tüm download thread’lerinin bitmesi dosyamızın başarı ile indirildiğinin göstergesi olacağından Notify metodunda bir event tetiklenmektedir. Dolayısı ile tüm thread’lerin herhangi bir zaman diliminde girebilecekleri bir metod olan Notify’ın koruma altına alınması gerekir. Bu koruma TCriticalSection.Enter/TCriticalSection.Leave ile sağlanır. TCriticalSection.Enter çağrısını geçtikten sonra, yani bir thread kod bloğumuzu işletirken bir başka thread TCriticalSection.Enter bloğunda sanki bir breakpoint varmış gibi beklemeye başlayacaktır. Taa ki TCriticalSection.Leave çağrısı işletilene kadar. Critical Section’lar şu bir kaç satırda izah edilebilecek kadar basit ve işlevsiz hususlar değillerdir. Multi-threaded programlamada son derece önemli kullanım sahaları vardır. Ancak konumuz bu olmadığı için daha derinlemesine anlatmak istemiyorum.

Critical section’ı neden kullandığımı izah ettikten sonra, biraz da TDownloader.Download metodundan bahsedelim. Bu metodun içinde TFileStream sınıfı vasıtası ile verilen isimdeki dosya verilen yolda oluşturulur. Ancak oluşturulma parametresindeki fmShareDenyNone‘a dikkatinizi çekmek isterim. TFileStream’in dosya erişimleri ile ilgili pek çok parametresi vardır. Yazmaya karşı korumalı, okumaya karşı korumalı, exclusive(yazma/okuma) korumalı, yada korumasız gibi. fmShareDenyNone parametresi ile oluşturduğumuz bu dosyanın başka uygulamalar/thread’ler tarafından okunabileceğini yada yazılabileceğini ifade etmiş oluyoruz.

Ardından TIdHTTP sınıfının Head metodunu çağırıyoruz. Bu metodu çağırmamızın sebebi, internet üzerinden download etmek istediğimiz dosyanın veri büyüklüğünü bilme zorunluluğumuz. Daha önce de ifade ettiğim gibi veri büyüklüğünü bilemediğimiz bir dosyayı parçalara bölemeyiz. Indy’nin pek çok bileşeninde Request ve Response property’lerine rastlamanız mümkün. Request genel anlamda karşı taraftan istekler; Response ise karşı tarafın verdiği yanıtlar olarak düşünülebilir. Biz uzaktaki bir dosyanın veri büyüklük bilgisini TIdHTTP’nin Head metodu ile istediğimize göre, aradığımız değer de Response(yanıt) içinde olacaktır. Response.ContentLength bize internet üzerindeki dosyanın veri büyüklüğünü verecektir.

Artık dosyanın uzunluk bilgisini aldıktan sonra diğer kısımlara geçebiliriz. Bu örneğin en can alıcı noktalarından bir tanesi ise aşağıdaki satırlarda gizlidir;

    if Size > 0 then
    begin
      SetLength(sBuff, Size);
      FillChar(Pointer(sBuff)^, Size, '0');
      fs.WriteBuffer(Pointer(sBuff)^, Size);
    end;

Yukarıdaki kod, sBuff isimli string değişken için hafızada dosyanın büyüklüğü kadar yer ayırmasını ardından içeriğinin sıfırlanmasını ve lokaldeki dosyamıza yazılmasını sağlar. Örneğin, indireceğimiz dosya 10 kb olsa, bu rutin hafızada 10 kb’lık bir yer ayıracak, içini sıfırlarla dolduracak ve hafızada ayrılmış veriyi bizim lokaldeki dosyamızın içine yazacak. Kısacası lokaldeki dosyamızın içinde 10240 adet 0(sıfır) olacak.

Peki bunu neden yapıyoruz ? Aslında nedeni thread kullanmamız. Bildiğiniz gibi thread’ler başına buyruk kod parçacıklarıdır. Kendi hallerinde çalışırlar, diğerlerine pek bulaşmazlar. Ancak tüm thread’lerin ortak kullanacakları bir kaynak varsa o zaman thread programlamada biraz dikkat gerekir. Bu örneğimizde tüm download thread’ler uzaktaki bir dosyanın belli byte’larını okuyacaklar bu hususta birbirlerinden bağımsızlar. Ancak hepsi aynı dosyaya yazacak. İşte bu hususta bağımsız değiller.. Risklere açık bir durum söz konusu. Lokaldeki dosyamıza yazacak olan thread’lerin ardışıl olarak çalışmaları söz konusu olsa idi, o zaman yine bir sorun olmayabilirdi. Kısa bir örnek vermek gerekir ise;

Diyelim ki internet üzerinden indirmek istediğimiz dosya bir text dosya olsun. İçerisinde de “Merhaba Dünya” yazısı olsun. Bu text dosyayı indirmek için iki ayrı thread’imiz olsun. Birinci thread’in “Merhaba” bilgisini, diğerinin ise “Dünya” bilgisini aldığını düşünelim. Yazacakları dosya aynı olduğu için, birinci thread’in dosyaya yazmaya başladığını düşünün. Bildiğiniz gibi TStream sınıfından türemiş tüm sınıflar herhangi bir stream’e veri yazdıklarında stream’in pozisyon bilgisini tutan sayacı arttırırlar. Öyle bir an geldiğini düşünün ki, birinci thread “Mer” yazabilmişken ikinci thread’de dosyayı açıp içine Dünya yazmaya başlamış olsun. Birinci thread “haba” yazıp dosyayı kapattığında aslında ikinci thread birinci thread’in yazdıklarının üstüne yazmış olur. Ve dosya o şekilde saklanır.

Bu ve buna benzer bir çok garip durumla karşılaşılabilir. Thread’lerin belirli bir sırada çalışması garanti olsa, yani önce birinci thread çalışıp sonlansa ve ardından ikincisi devreye girip sonlansa tahmin edeceğiniz gibi hiç bir sorun olmaz. Ancak, bu ihtimalli bir durumdur. Birinci thread’in indirmesi gereken veriler daha uzun olabilir ve ikincisinin çalışma zamanından daha uzun bir çalışma zamanına sahip olabilir. Yine makalelerimizden birisinde daha önce yazdığımız gibi, Thread’leri sıraya soksak bu seferde thread kullanmamızın bir anlamı kalmayacak. Biz indirme işleminin ve yazma işleminin paralel yürütülmesini istiyoruz.

İşte tüm bu sebeplerden ötürü, benim aklıma gelen ilkel yöntem internet üzerinden indirilecek olan dosyanın büyüklüğü kadar lokal dosyada sıfır oluşturmak. Bu durumda her thread lokal dosyada hangi pozisyondan başlayarak kaç byte yazacağını bildiği için, diğer thread’lerin yazacağı bilgilerle çakışmamış olacağız.

Metin: Merhaba Dünya
Thread 1 : 1-8 arası karakterleri indir.
Thread 2 : 9-13 arası karakterleri indir.

Thread 1 : Lokal dosyanın 1 pozisyonuna konumlan. 8 byte veri yaz.
Thread 2 : Lokal dosyanın 9 pozisyonuna konumlan 5 byte veri yaz.

Yukarıdaki senaryodan görebileceğiniz üzere iki yada daha fazla thread aynı anda aynı dosyaya erişse ve o dosya üzerinde yazma işlemi yapsa da herhangi bir sorun oluşmayacaktır. Çünkü her thread dosyanın ayrı bir yerine yazmaktadır.

Bu kısmı da anlattıktan sonra, TDownloader.Download metoduna geçilen Part parametresi üzerinde durmamız gerekiyor. Part parametresi indirme işlemi için kaç adet thread kullanmak istediğimizi ifade ediyor. Part parametresinin değerine göre internet üzerinden indirilecek olan dosyanın hangi byte aralıklarında indirilmesi gerektiğini ve lokaldeki dosyaya hangi aralıklarla yazmamız gerektiğini bulabiliyoruz. Örneğin indirmek istediğimiz dosya, 123.456 byte olsun ve Part parametremizde 10 olsun. Bu durumda 123.456 / 10 = 12.345 byte’lık parçalar halinde indirme yapacağız demektir. Bu da; 0-12345 , 12346-24691, 24692-37036 … gibi aralıklara sahip olacağız anlamına gelir. TDownloader.Download metodunun geri kalan kısımları bu aralık değerlerini hesaplamak ve download thread’lerini çalıştırmaktan ibaret.

Şimdi arzu ederseniz, download işlemini yapan thread’imizin kodlarına yakından bir bakalım:

{ TDownloadThread }

constructor TDownloadThread.Create(const AOwner : TDownloader; const AUrl, AFileName : String; ARange : TRange);
begin
  inherited Create(true); // Thread durur vaziyette olsun..
  FreeOnTerminate := true; // işi bitince free olsun..

  fFileName := AFileName;
  fRange := ARange;
  fUrl := AUrl;
  fOwner := AOwner;
end;

procedure TDownloadThread.Execute;
var
  http: TIdHttp;
  fs  : TFileStream;
  ms  : TMemoryStream;
begin
  inherited;

  http:= TIdHttp.Create(nil);
  fs := TFileStream.Create(fFileName, fmOpenWrite or fmShareDenyNone);
  ms := TMemoryStream.Create;

  try
    http.Request.Range := Format('%d-%d', [fRange.StartPosition, fRange.EndPosition]);
    http.Get(fUrl, ms);

    fs.Position := fRange.StartPosition;
    ms.Position := 0;
    fs.CopyFrom(ms, ms.Size);
  finally
    fs.Free;
    ms.Free;
    http.Disconnect;
    http.Free;
  end;

  fOwner.Notify;
end;

Thread’imiz ilk oluşturulduğunda henüz uyur vaziyettedir. Oluşturulma kodları tamamlanınca TDownloader.Download metodunun içindeki Resume çağrısı vasıtası ile çalıştırılacak ve Execute metoduna dallanılacaktır. Execute metodunda, lokalimizdeki dosyanın sadece yazma amacı ile açıldığını gözlemleyebilirsiniz. Ardından en önemli komut olarak Request.Range’e internet üzerinden indirilecek dosyanın hangi byte’larının indirileceği bilgisi aktarılıyor. Ardından Get metodu bizim belirttiğimiz Url’deki dosyanın Range property’sinde belirttiğimiz başlangıç ve bitiş byte’ları kadar bilgiyi okuyup ikinci parametresindeki TStream türündeki stream’e yazıyor. Biz burada internetten indirmek istediğimiz dosyanın ilgili byte’larını bir TMemoryStream‘de tutmayı uygun bulduk.

Ardından yine can alıcı bir nokta olarak, TMemoryStream sınıfından türemiş nesnemizin pozisyon işaretçisini en başa aldık. Ancak TFileStream türündeki nesnemizinkini ise, thread’in indirmeye başladığı başlangıç değerine aldık ;) Eğer bir sihir varsa bu makalede o da bu kısımdır :) Sonrasında ise CopyFrom ile TMemoryStream’den okuyup TFileStream’e yazdık. Ve nihayet thread’imizin işini bitirdiğini belirtmek maksadı ile TDownloader nesnemize Notify metodunu çağırmak sureti ile haber verdik.

Bütün bu işlem döngüsü, tüm thread’ler için tamamlandığında, dosyamız internetten lokalimize indirilmiş oluyor. Kısa bir kullanımını verip, makaleyi tamamlayalım:

  TForm1 = class(TForm)
  ..
  ..
  ..
  private
    procedure DownloadComplete(const FileName : String; const WorkTime : DWord);
  public
  end;

var
  downloader : TDownloader;
..
..
..
// Memo1 TMemo türündedir.
procedure TForm1.DownloadComplete(const FileName: String;
  const WorkTime: DWord);
begin
  Memo1.Lines.Add(FileName + ' download işlemi ' + InttoStr(WorkTime) + ' ms. sürdü.');
  if downloader <> nil then FreeAndNil(downloader);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(downloader) then downloader := TDownloader.Create;
  downloader.OnDownloadComplete := DownloadComplete;
  downloader.Download('http://www.tugrulhelvaci.com/wp-content/uploads/turboman.jpg', 'c:\turboman.jpg', 5);
end;

Bir sonraki makalemizde görüşmek ümidi ile,
Saygılar, sevgiler..

“TIdHTTP Partial Download(Parça Parça Download)” için 20 Yorum

  1. Olcay DAĞLI diyor ki:

    Hocam gerçekten harika olmuş, kesinlikle her programcının, yazdıkları programların exe update işlemlerinde kullanması gereken güzel bir başucu kodu olmuş. Eline emeğine sağlık…

  2. Önder Önvermez diyor ki:

    Teşekkürler.

  3. Fatih diyor ki:

    Slm;

    Yazınızı okudum ancak deneyemedim acaba bana yardımcı olabilirmisiniz. Bu kodların çalışan halleri mevcutsa almak isterim . Teşekkürler.

  4. Tuğrul HELVACI diyor ki:

    Nerede sorun yaşadınız Fatih bey ? Detaylandırabilirseniz yardımcı olabilirim.

  5. mehmet diyor ki:

    Hocam makalenizi okudun.Ancak pek çözemedim.
    Bir örnek verip kafamızdaki soruları netleştirebilirmisiniz.
    Saygılar…

  6. Tuğrul HELVACI diyor ki:

    Bu makalede neyi çözemediniz ? En son bölümde kullanımına ait bir örnek de vermiştim.

  7. Mehmet diyor ki:

    Hocam Makaleniz çok güzel .
    Ben delphiyi hobi olarak kullanıyorum.ama verdiğiniz kodları delphi nin hangi alanlarına yazacağımı çözemedim.Bu dosyayı bana gönderemezmisiniz.Rica Etsem

    Saygılarımla…

  8. Tuğrul HELVACI diyor ki:

    Mehmet Bey, burada paylaştığım kodları Delphi’de nasıl kullanacağınızı bilemiyorsanız inanın projenin kaynak kodlarını göndermem size hiç bir fayda sağlamayacaktır. Mümkün mertebe ileri seviye konuları paylaşmaya gayret ediyorum sitemde. Paylaşımlarımın sizin için daha faydalı olabilmesi adına Delphi konusundaki temel bilgilerinizi biraz daha genişletmeyi tercih edebilirsiniz.

  9. Mehmet diyor ki:

    Hocam eleştirinizde haklısınız ama o kadarda bilmiyor sayılmam herşey tamam da sadece şurda bir hatam var

    Section : TCriticalSection;

    [DCC Error] Unit1.pas(37): E2003 Undeclared identifier: ‘TCriticalSection’

    bu hatayı veriyor burda yardim ederseniz sevinirim.

    Saygılarımla..

  10. Tuğrul HELVACI diyor ki:

    TCriticalSection SyncObjs.pas dosyasında tanımlanmıştır. Uses kımına SyncObjs eklemeniz gerekiyor.

  11. mahmut diyor ki:

    Hocam elinize sağlık dökümanlarınız gerçekten harika.

    Takıldığım bir konu var. Partial download ilerlemesini progressbar üzerinde nasıl gösterebiliriz ?

  12. ANIL diyor ki:

    Direk olarak yazılı ornek bir sources daha etkili olurdu. eğer elinde varsa sources şeklinde gönderirimisin lütfen?

  13. ANIL diyor ki:

    Merhaba, Kalan boyutu ve indirme hızını nasıl öğreniceğiz bunda aceba?

  14. Ali Gonenc diyor ki:

    Merhaba
    lisansli delphi 7 kullanicisiyim
    delphi 7 de
    http.Request.Range := Format(‘%d-%d’, [fRange.StartPosition, fRange.EndPosition]);

    Request.Range “Range” malesef yok..
    indy versionunu 10.1.5 ‘e yukselltim sorun devam etti

    kod olarak
    http.Request.ContentRangeStart:=fRange.StartPosition;
    http.Request.ContentRangeEnd :=fRange.EndPosition;
    denedim fakat olmadi

    yardimci olursaniz cok sevinirim..

  15. Tuğrul HELVACI diyor ki:

    Indy’nin 10x sürümlerinde Range özelliği olmalı.. Ama sizin mesajınızdan sonra küçük bir araştırma yaptım bende, sanırım Range property’si depreceted olmuş, onun yerine “Ranges” kullanılmasını öneriyorlar.

  16. Rahmi diyor ki:

    Merhaba
    Dostum yazdığın makale çok işime yaradı fakat işin içinden çıkamadığım bir konu var.

    Download etme esnasında PAUSE etme ve devam etme ?
    Birkaç kod üzerinde oynama yaptım ama bir türlü çıkamadım işin içinden
    // PART_2 Text dosyasında boyut varsa StartPosition ayarla.

    if StrToInt(Form1.Part_2.Text) > 0 then
    Ranges[0].StartPosition := StrToInt(Form1.Part_2.Text)
    else
    Ranges[0].StartPosition := 0;

    //
    procedure TDownloadThread.Execute;
    .
    ..
    ..
    http.Name := ‘A_’ + InttoStr(fRange.Sira);
    http.OnWork := Form1.IdHTTP1Work;
    // Olusan objeye isim verdim.

    procedure TForm1.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
    AWorkCount: Int64);

    if (ASender as TIdHTTP).Name = ‘A_0′ then
    Part_2.Text := Inttostr((AWorkCount div 1024));

    Manuel elle yazıdıgımda P2.text objesine devam etmesi gerekiyor ama sıfırdan baslıyor sebep nedir sizce?

    • Tuğrul HELVACI diyor ki:

      Bu yapı pause edilmeye pek de müsait bir yapı değil. Çünkü belirli aralıktaki btye’ları TIdHttp’nin get metodu indiriyor. Dolayısı ile pause kodunun TIdHttp içinde yazılması icap eder ki bu da pek meşakkatli bir yöntem. Bu yapı yerine yine sitemde olan bulabileceğiniz BITS makalesi tam da sizin istediğiniz işi yapar. Hem o makaleden de görebileceğiniz gibi; BITS ile yapacağınız download’lar sistemi ve bağlantınızı zorlamayacak downloadlardır. İstediğiniz an pause edip istediğiniz an devam ettirebilirsiniz. Ayrıca; makinanızı kapatsanız dahi otomatikman kaldığı yerden download’a devam edebilme gibi güzel yetenekleri vardır. Dolayısı ile ; sitemde bulabileceğiniz BITS makalesine bir göz gezdirmenizde fayda olacağı kanaatindeyim.

Rahmi için yorum yazın