我想从专门用于下载的单独线程中下载Delphi程序中的文件。
问题是主程序可以随时关闭(因此下载线程也可以随时终止)。因此,即使没有连接或服务器滞后宝贵的秒钟,我还需要一种方法在一两秒内终止下载线程。
你们建议使用什么功能?
我已尝试使用InterOpenURL / InternetReadFile,但它没有超时参数。它有一个异步版本,但我找不到任何正在运行的Delphi示例,我不确定异步版本是否会保护我免受挂起......
以前建议使用套接字,但TClientSocket似乎也没有超时功能。
我需要做好充分的准备,因此如果用户在他/她的计算机上遇到Internet连接问题,或者网络服务器一直滞后,我的应用程序在关闭之前就不会挂起。
在回答我不想使用任何第三方组件和Indy时请记住。非常感谢任何示例代码。
谢谢!
答案 0 :(得分: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
方法的一部分,而您不需要DownloadAbort
;你正在检查
if Terminated then
Exit;
答案 1 :(得分:2)
TWinSocketStream
超时。您基本上创建了一个阻塞套接字,然后使用该套接字创建一个TWinSocketStream进行读/写。 (有点像使用StreamWriter)。然后循环直到连接关闭,线程终止,或者达到预期的字节数。有一个WaitForData()允许您检查传入的数据是否超时,因此您永远不会“锁定”超过该超时值。
但是,您必须自己处理http进程。即发送'GET',然后读取响应头以确定预期的字节数,但这并不太难。
答案 2 :(得分: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;
答案 3 :(得分:1)
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属性指向Internet FileName是本地文件 }