7

ダウンロード専用の別のスレッドで Delphi プログラムからファイルをダウンロードしたいと考えています。

問題は、メイン プログラムがいつでも閉じられる可能性があることです (したがって、ダウンロード スレッドもいつでも終了される可能性があります)。そのため、接続がない場合やサーバーが貴重な数秒間遅延した場合でも、ダウンロード スレッドを 1 ~ 2 秒以内に終了する方法が必要です。

皆さんはどの機能を使うのがオススメですか?

InterOpenURL/InternetReadFile を試してみましたが、タイムアウト パラメータがありません。非同期バージョンはありますが、動作する Delphi の例が見つかりませんでした。また、非同期バージョンがハングから保護してくれるかどうかもわかりません...

以前からソケットの使用を勧められていましたが、TClientSocket にもタイムアウト機能がないようです。

ユーザーのコンピューターでインターネット接続の問題が発生したり、Web サーバーの動作が遅くなったりしても、アプリケーションを閉じる前にハングしないように、十分に準備する必要があります。

サードパーティのコンポーネントも Indy も使用したくないということを回答する際は、心に留めておいてください。サンプルコードは大歓迎です。

ありがとうございました!

4

4 に答える 4

5

これは機能します。

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は必要ありません。DownloadAbortintead、あなたはチェックします

if Terminated then
  Exit;
于 2010-08-23T15:16:25.200 に答える
2

TWinSocketStreamタイムアウトがあります。基本的にブロッキング ソケットを作成し、そのソケットを使用して読み取り/書き込み用の TWinSocketStream を作成します。(StreamWriterを使用するようなものです)。次に、接続が閉じられるか、スレッドが終了するか、予想されるバイト数に達するまでループします。タイムアウトを使用して受信データをチェックできる WaitForData() があるため、そのタイムアウト値を超えて「ロック」されることはありません。

ただし、http プロセスは自分で処理する必要があります。つまり、'GET' を送信し、応答ヘッダーを読み取って予想されるバイト数を判断しますが、それほど難しくありません。

于 2010-08-23T17:54:04.947 に答える
2

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;
于 2010-08-24T15:31:12.607 に答える
1

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プロパティはインターネットを指しますFileNameはローカルファイルです}

于 2010-08-24T22:42:13.857 に答える