tags:

views:

124

answers:

2

I want to download a file from internet and I imagine this should be a simple task. Trying several different approaches I have found that each one has its own drawback. The main issues are:

  • Application freezes until it downloads the file
  • Application freezes forever if the Internet connection is lost/server does not respond.

(details:

http://stackoverflow.com/questions/3122306/how-to-retrieve-a-file-from-internet-via-http
http://stackoverflow.com/questions/3135003/the-connection-does-not-timeout-while-downloading-file-from-internet )

So, finally I used the suggestions I got from several people to use "pro" libraries such as Indy. However, Indy is not much better than the pieces of code I have tried (but it is way much larger and difficult to maintain). While using Indy the application does not freezes only for short periods so it is still (somehow) usable. However, the application cannot be shut down until the download finishes (never if the Internet connections gets broken).

Other people reported the same problem: http://borland.newsgroups.archived.at/public.delphi.internet.winsock/200609/0609079112.html
https://forums.embarcadero.com/thread.jspa?threadID=25199&tstart=90

So, there is some hacking I had to do to TIDAntiFreeze in order to make it work?

Also, the ConnectTimeout property is not recognized.

fIDHTTP := TIDHTTP.Create(NIL);
fIDHTTP.ConnectTimeout:=5000;

Should I drop Indy and return to original idea of downloading the file in a separate thread and end the thread when it does not respond (at least this way I get rid of 3rd party libraries)? There will be unforeseen side effects if I do this?

Using: Delphi 7, Indy 10.1.5 10.5 (probably).

Thanks

A: 

It's not too difficult to solve these sorts of problems. The first thing you have to do is make sure that you have properly handled error handling. If something fails then make sure everything cleans up properly. Beyond that make sure the downloading code is part of a separate thread. If there is any problem you can always terminate the thread from your main program. Here's the code (for downloading only, not the threading) which is working fine for me.

with TDownloadURL.Create(nil) do
  try
    URL := 'myurltodownload.com';
    filename := 'locationtosaveto';
    try
      ExecuteTarget(nil);
    except
      result := false;
    end;
    if not FileExists(filename) then
      result := false;
  finally
    clear;
    free;
  end;
Daisetsu
This doesn't cover the main point of this discussion. Quote: "Application freezes until it downloads the file."
Altar
Read my post again, and also refer to the answer by Cosmin Prund. We both are saying you MUST USE THREADS else there's no way to prevent this. Even with Indy you need to use a thread, there is no way around it. You said that Indy was too bulky for your needs so I provided a tested alternative in conjunction with saying that it MUST be threaded. I don't see how this answer doesn't cover your main point. Answer: Thread it.
Daisetsu
Accepted answer.
Altar
Daisetsu, please see this post: http://stackoverflow.com/questions/3526749/use-of-try-finally-except
Altar
+2  A: 

You probably need to use Indy the Indy way: using threads. Indy was specifically designed to work in blocking mode, because that's how most Internet protocols work (example: with HTTP, at protocol level, you send a request then you read the response. You dont send AND receive at the same time). TIdAntiFreeze is supposed to help you use some Indy functionality without dealing with threads; I never used that because, at least conceptualy, it's an ugly hack.

If don't want to deal with Threads then you should take a look at ICS ( link to ICS home page ). ICS was designed to be used in Async mode, without threading. It doesn't need the equivalent of TIdAntiFreeze because it's not blocking. You start an download and you handle some events to get progress and completion notifications. ICS is just as well-known, professional and wildly used as Indy.

Cosmin Prund
After circling around threads it seems it is the ONLY solution! Thanks. +1
Altar