携帯版
5090 (isweb) + 79520 (Vector) + Counter by XREA.COM


メニュー
アンテナ
Autch.net > 小ネタ > 簡単に http 非同期ファイル取得を行うには Last-Modified: 2008-09-10 16:40:03 (JST)

[Delphi] 簡単に http 非同期ファイル取得を行うには

概要

WinINet ユニットに宣言されている関数群を使うことにより, 単純なファイルのダウンロード程度なら非常に簡単に実現することができるが, これらはそのまま使うと同期ダウンロードとなり,ダウンロード等の処理が完了するまで 一切のコードを実行できなくなってしまう。

そうはならない非同期関数もあるのだが,これらは扱いが煩雑で,Delphi にも実装例はあるものの,同期式のときとは比較にならないほどのコーディングを 要求される。

ここでは,その WinINet 同期型関数をスレッドから扱うことにより, 少ないコード量で非同期ダウンロードもどきを実装するという,かなりアレな手法を紹介する。

コード

HTTPSyncFileDownloaderThread.pas
unit HTTPSyncFileDownloaderThread;

interface

uses
  Classes, Windows, SysUtils, WinInet, Forms;

type
  THTTPSyncFileDownloader = class(TThread)
  private
    UserAgent, URL, Headers: String;
    LastModified: TDateTime;
  protected
    procedure Execute; override;
  public
    stream: TStream;
    constructor Create(aUserAgent, aURL, aHeaders: String;
                         pfnCallback: TNotifyEvent; aStream: TStream); overload;
  end;

implementation

// THTTPSyncFileDownloader

procedure THTTPSyncFileDownloader.Execute;
var
  hSession: HINTERNET;
  hService: HINTERNET;
  lpBuffer: array[0..1024] of Byte;
  dwBytesRead: DWORD;
  szHeader: string;
  dwSize, Reserved: DWORD;
  ft1, ft2: FILETIME;
  httpLastModified: TSystemTime;
begin
  inherited;

  hSession := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    if Assigned(hSession) then
    begin
      szheader := Headers;
      SetLength(szHeader, Length(szHeader));
      hService := InternetOpenUrl(hSession, PChar(URL), PChar(szHeader), $ffffffff,
                                  INTERNET_FLAG_RELOAD, 0);
      try
        if Assigned(hService) then
        begin
          dwBytesRead := 1024;
          while dwBytesRead = 1024 do
          begin
            // 同期モードのため,InternetReadFile() は,
            // データがまだ来ていないときには待ち続ける。
            // そのため,dwBytesRead
            // 理由が何であれダウンロードが終了したと
            // 考えることができる。
            InternetReadFile(hService, @lpBuffer, 1024, dwBytesRead);
            stream.WriteBuffer(lpBuffer, dwBytesRead);
            Sleep(10);
          end;

          // touch. 必要なければ削除しても良い。
          dwSize := sizeof(httpLastModified);
          Reserved := 0;
          HttpQueryInfo(hService, HTTP_QUERY_LAST_MODIFIED or HTTP_QUERY_FLAG_SYSTEMTIME,
                                  @httpLastModified, dwSize, Reserved);
          SystemTimeToFileTime(httpLastModified, ft2);
          FileTimeToLocalFileTime(ft2, ft1); // かなり適当
          FileTimeToSystemTime(ft1, httpLastModified);

          LastModified := SystemTimeToDateTime(httpLastModified);
          // touch ここまで
        end;
      finally
        InternetCloseHandle(hService);
      end;
    end;
  finally
    InternetCloseHandle(hSession);
  end;
end;

constructor THTTPSyncFileDownloader.Create(aUserAgent, aURL, aHeaders: String;
                                          pfnCallback: TNotifyEvent; aStream: TStream);
begin
  inherited Create(false);
  FreeOnTerminate := true;

  UserAgent := aUserAgent;
  URL := aURL;
  Headers := aHeaders;

  OnTerminate := pfnCallback;
  stream := aStream;
end;
end.

解説

WinINet 同期型関数を用いた,HTTP 擬似非同期ファイルダウンロードスレッド THTTPSyncFileDownloader を定義している(なぜ THTTPAsyncFileDownloader ではないのかというと,実装の方法に注目して名前をつけたため)。

このスレッドは,コンストラクタ Create() で指定された URL のファイルを取得し, 同じく指定された TStream の下位クラスにその内容を書き込む。

コンストラクタ Create() で,ダウンロードすべきオブジェクトの URL や 追加ヘッダー,サーバへ通知する User-Agent, ダウンロード完了時に呼び出されるコールバック手続きの設定を行っている。 このとき,上位クラスのコンストラクタを,CreateSuspended 引数を False にして呼び出しているため, このスレッドは Create() すると直ちに動き出す。また,FreeOnTerminate プロパティを True にしているため,ダウンロードが完了すると,このスレッドは自動的に破棄される。

ソースコード中で touch と記されている部分は,指定されたファイルの Last-Modified を メンバ変数 LastModified に格納している。途中の時刻関数の連続は,http で取得された GMT 時刻を, 現在のシステムロケールに変換している。

注意

このコードは実用的なコードになるためのいくつかの要素を省略している。たとえば, データ取得ループでは Terminated プロパティをチェックしていない。

出典

monazilla.org(w の WinINet サンプル を改変した,auROra のソースコード HTTPSyncFileDownloader.pas より


Autch.net > 小ネタ > 簡単に http 非同期ファイル取得を行うには Last-Modified: 2008-09-10 16:40:03 (JST)
Valid XHTML 1.0! Valid CSS! Made with Cascading Style Sheets Powered by PHP Powered by Smarty
転載・引用・リンク・アンリンク自由。一切のコンテンツは無保証。
Copyright © 2000 - 2008, Autch.net. "gray_forest" theme designed by OCEAN-NET.