我想使用TIdHttp(Indy10)实现一个简单的http下载器。我从互联网上找到了两种代码示例。不幸的是,他们都没有100%满足我。这是代码,我想要一些建议。
变体1
var
Buffer: TFileStream;
HttpClient: TIdHttp;
begin
Buffer := TFileStream.Create('somefile.exe', fmCreate or fmShareDenyWrite);
try
HttpClient := TIdHttp.Create(nil);
try
HttpClient.Get('http://somewhere.com/somefile.exe', Buffer); // wait until it is done
finally
HttpClient.Free;
end;
finally
Buffer.Free;
end;
end;
代码紧凑且易于理解。问题是它在下载开始时分配磁盘空间。另一个问题是我们无法直接在GUI中显示下载进度,除非代码在后台线程中执行(或者我们可以绑定HttpClient.OnWork事件)。
变体2:
const
RECV_BUFFER_SIZE = 32768;
var
HttpClient: TIdHttp;
FileSize: Int64;
Buffer: TMemoryStream;
begin
HttpClient := TIdHttp.Create(nil);
try
HttpClient.Head('http://somewhere.com/somefile.exe');
FileSize := HttpClient.Response.ContentLength;
Buffer := TMemoryStream.Create;
try
while Buffer.Size < FileSize do
begin
HttpClient.Request.ContentRangeStart := Buffer.Size;
if Buffer.Size + RECV_BUFFER_SIZE < FileSize then
HttpClient.Request.ContentRangeEnd := Buffer.Size + RECV_BUFFER_SIZE - 1
else
HttpClient.Request.ContentRangeEnd := FileSize;
HttpClient.Get(HttpClient.URL.URI, Buffer); // wait until it is done
Buffer.SaveToFile('somefile.exe');
end;
finally
Buffer.Free;
end;
finally
HttpClient.Free;
end;
end;
首先我们从服务器查询文件大小,然后我们下载文件内容。检索到的文件内容将在完全收到后保存到磁盘。潜在的问题是我们必须向服务器发送多个GET请求。我不确定某些服务器(例如megaupload)是否可能限制特定时间段内的请求数量。
我的期望
感谢任何提示。
答案 0 :(得分:26)
变体#1是最简单的,也就是Indy的使用方式。
关于磁盘分配问题,您可以从TFileStream
派生一个新类,并覆盖其SetSize()
方法,不执行任何操作。 TIdHTTP
仍将在适当时尝试预分配文件,但实际上不会分配任何磁盘空间。写入TFileStream
将根据需要增加文件。
关于状态报告,TIdHTTP
为此目的有OnWork...
个事件。 AWorkCountMax
的{{1}}参数将是已知的实际文件大小(响应未分块),如果未知,则为0。 OnWorkBegin
事件的AWorkCount
参数将是到目前为止已传输的累计字节数。如果文件大小已知,则只需将OnWork
除以AWorkCount
并乘以100即可显示总百分比,否则只需显示AWorkCountMax
值。如果您想显示转移的速度,可以根据AWorkCount
值与多个AWorkCount
事件之间的时间间隔的差异来计算。
试试这个:
OnWork
type
TNoPresizeFileStream = class(TFileStream)
procedure
procedure SetSize(const NewSize: Int64); override;
end;
procedure TNoPresizeFileStream.SetSize(const NewSize: Int64);
begin
end;
答案 1 :(得分:4)
以下是一个示例,说明如何使用OnWork组件显示进度条:
Download a File from internet programatically with an Progress event using Delphi and Indy
您不必担心磁盘分配。分配的磁盘空间实际上并未写入,因此不会损坏磁盘。很高兴它被分配,以便其他进程无法声明磁盘空间并让你的空间不足!
答案 2 :(得分:2)
不要忘记为Variant 2添加此内容
: Else HttpClient.Request.ContentRangeEnd := FileSize;
替换
if Buffer.Size + RECV_BUFFER_SIZE < FileSize then
HttpClient.Request.ContentRangeEnd := Buffer.Size + RECV_BUFFER_SIZE - 1;
通过
if Buffer.Size + RECV_BUFFER_SIZE < FileSize then
HttpClient.Request.ContentRangeEnd := Buffer.Size + RECV_BUFFER_SIZE - 1;
Else HttpClient.Request.ContentRangeEnd := FileSize;