Загрузка файла из Интернета при возможности прервать скачать в любое время

Я хотел бы загрузить файл из моей программы Delphi в отдельном потоке, посвященном загрузке.

проблема в том, что основная программа может быть закрыта в любое время (таким образом, поток загрузки может быть также прерван в любое время). Поэтому, даже если нет соединения или сервер зависает на драгоценные секунды, мне нужен способ завершить поток загрузки в секунду или две.

Какую функцию вы, ребята, рекомендуете использовать?

I ' Мы экспериментировали с InterOpenURL / InternetReadFile, но у него нет параметра времени ожидания. У него действительно есть асинхронная версия, но я не смог найти ни одного работающего примера Delphi, и я не уверен, защитит ли меня асинхронная версия от зависаний ...

Использование сокетов было рекомендовано мне ранее, но TClientSocket не ' Похоже, у него также есть функция тайм-аута.

Мне нужно быть полностью подготовленным, поэтому, если у пользователя проблемы с подключением к Интернету на его / ее компьютере или веб-сервер продолжает зависать, мое приложение не зависает перед закрытием.

Имейте в виду, когда отвечаете, что я не хочу использовать ни сторонние компоненты, ни Indy. Любой пример кода с благодарностью.

Спасибо!

7
задан Steve 23 August 2010 в 14:27
поделиться

4 ответа

TWinSocketStream имеет таймаут. По сути, вы создаете блокирующий сокет, а затем создаете TWinSocketStream, использующий этот сокет для чтения/записи. (что-то вроде использования StreamWriter). Затем вы выполняете цикл до тех пор, пока соединение не будет закрыто, поток не будет завершен, или пока не будет получено ожидаемое количество байт. Есть функция WaitForData(), которая позволяет вам проверять входящие данные с таймаутом, так что вы никогда не будете "заперты" после этого значения таймаута.

Однако, вам придется самостоятельно обрабатывать процесс http. т.е. посылать 'GET', а затем читать заголовок ответа, чтобы определить, сколько байт ожидать, но это не слишком сложно.

2
ответ дан 7 December 2019 в 01:14
поделиться

Спасибо GrandmasterB, вот код, который мне удалось собрать: (он находится в блоке Execute моего потока)

var
  Buffer: array [0..1024 - 1] of Char;
  SocketStream: TWinSocketStream;
  RequestString: String;
  BytesRead: Integer;
begin
  try
    ClientSocket.Active := true;
    DownloadedData := '';
    FillChar(Buffer, SizeOf(Buffer), #0);

    if not Terminated then
    begin
      // Wait 10 seconds
      SocketStream := TWinSocketStream.Create(ClientSocket.Socket, 10000);
      try
        // Send the request to the webserver
        RequestString := 'GET /remotedir/remotefile.html HTTP/1.0'#13#10 +
          'Host: www.someexamplehost.com'#13#10#13#10;
        SocketStream.Write(RequestString[1], Length(RequestString));

        // We keep waiting for the data for 5 seconds
        if (not Terminated) and SocketStream.WaitForData(5000) then
          repeat
            // We store the data in our buffer
            BytesRead := SocketStream.Read(Buffer, SizeOf(Buffer));

            if BytesRead = 0 then
              break
            else
              DownloadedData := DownloadedData + Buffer;
          until Terminated or (not SocketStream.WaitForData(2000));
      finally
        // Close the connection
        SocketStream.Free;
        if ClientSocket.Active then
          ClientSocket.Active := false;
      end;
    end;
  except
  end;

Вы должны поместить это в конструктор потока:

  ClientSocket := TClientSocket.Create(nil);
  ClientSocket.Host := 'www.someexamplehost.com';
  ClientSocket.Port := 80;
  ClientSocket.ClientType := ctBlocking;

  inherited Create(false);  // CreateSuspended := false;

А это в деструктор Теги :

  ClientSocket.Free;
  inherited;
2
ответ дан 7 December 2019 в 01:14
поделиться

От delphi.about.com


uses ExtActns, ...

type
   TfrMain = class(TForm)
   ...
   private
     procedure URL_OnDownloadProgress
        (Sender: TDownLoadURL;
         Progress, ProgressMax: Cardinal;
         StatusCode: TURLDownloadStatus;
         StatusText: String; var Cancel: Boolean) ;
   ...

implementation
...

procedure TfrMain.URL_OnDownloadProgress;
begin
   ProgressBar1.Max:= ProgressMax;
   ProgressBar1.Position:= Progress;
end;

function DoDownload;
begin
   with TDownloadURL.Create(self) do
   try
     URL:='http://0.tqn.com/6/g/delphi/b/index.xml';
     FileName := 'c:\ADPHealines.xml';
     OnDownloadProgress := URL_OnDownloadProgress;

     ExecuteTarget(nil) ;
   finally
     Free;
   end;
end;

{ Заметка: Свойство URL указывает на Интернет Имя_файла — локальный файл }

1
ответ дан 7 December 2019 в 01:14
поделиться

Это работает.

var
  DownloadAbort: boolean;

procedure Download(const URL, FileName: string);
var
  hInet: HINTERNET;
  hURL: HINTERNET;
  Buffer: array[0..1023] of AnsiChar;
  BufferLen, amt: cardinal;
  f: file;
const
  UserAgent = 'Delphi Application'; // Change to whatever you wish
begin
  DownloadAbort := false;
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    hURL := InternetOpenUrl(hInet, PChar(URL), nil, 0, 0, 0);
    try
      FileMode := fmOpenWrite;
      AssignFile(f, FileName);
      try
        Rewrite(f, 1);
        repeat
          InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
          BlockWrite(f, Buffer[0], BufferLen, amt);
          if DownloadAbort then
            Exit;
        until BufferLen = 0;
      finally
        CloseFile(f);
      end;
    finally
      InternetCloseHandle(hURL);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

На практике приведенный выше код будет частью метода Execute вашего потока, и вам не нужно DownloadAbort; вместо этого вы делаете чек

if Terminated then
  Exit;
5
ответ дан 7 December 2019 в 01:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: