Delphi 使用TIdHttp逐步下载文件
我想使用TIdHttp(Indy10)实现一个简单的http下载程序。我在网上找到了两种代码示例。不幸的是,没有一个能让我100%满意。这是代码,我需要一些建议Delphi 使用TIdHttp逐步下载文件,delphi,http,download,indy,idhttp,Delphi,Http,Download,Indy,Idhttp,我想使用TIdHttp(Indy10)实现一个简单的http下载程序。我在网上找到了两种代码示例。不幸的是,没有一个能让我100%满意。这是代码,我需要一些建议 变体1 var Buffer: TFileStream; HttpClient: TIdHttp; begin Buffer := TFileStream.Create('somefile.exe', fmCreate or fmShareDenyWrite); try HttpClient := TIdHtt
变体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;
const
RECV_BUFFER_SIZE=32768;
变量
HttpClient:TIdHttp;
文件大小:Int64;
缓冲区:TMemoryStream;
开始
HttpClient:=TIdHttp.Create(nil);
尝试
HttpClient.Head('http://somewhere.com/somefile.exe');
FileSize:=HttpClient.Response.ContentLength;
缓冲区:=TMemoryStream.Create;
尝试
而Buffer.Size
首先,我们从服务器查询文件大小,然后将文件内容分块下载。检索到的文件内容完全接收后将保存到磁盘。潜在的问题是我们必须向服务器发送多个GET请求。我不确定某些服务器(如megaupload)是否会限制特定时间段内的请求数量
我的期望
如有任何提示,我们将不胜感激 下面是一个示例,演示如何使用组件OnWork来显示进度条: 您不应该担心磁盘分配。分配的磁盘空间实际上没有写入,因此不会损坏磁盘。很高兴它被分配了,这样就不可能有另一个进程占用磁盘空间而让您耗尽空间 变体#1是最简单的,也是印第的用意 关于磁盘分配问题,您可以从
TFileStream
派生一个新类,并重写它的SetSize()
方法以不执行任何操作TIdHTTP
仍将在适当时尝试预分配文件,但实际上不会分配任何磁盘空间。写入TFileStream
将根据需要增长文件
关于状态报告,TIdHTTP
有OnWork…
事件用于此目的。OnWorkBegin
的AWorkCountMax
参数将是实际文件大小(如果已知)(响应未分块),如果未知,则为0。OnWork
事件的AWorkCount
参数将是迄今为止已传输的累积字节数。如果已知文件大小,只需将AWorkCount
除以AWorkCountMax
并乘以100即可显示总百分比,否则只需显示AWorkCount
值本身即可。如果要显示传输速度,可以根据a工作计数
值与多个on work
事件之间的时间间隔之差来计算传输速度
试试这个:
type
TNoPresizeFileStream = class(TFileStream)
procedure
procedure SetSize(const NewSize: Int64); override;
end;
procedure TNoPresizeFileStream.SetSize(const NewSize: Int64);
begin
end;
类型
TSomeClass=class(TSomething)
...
TotalBytes:In64;
LastWorkCount:Int64;
拉斯蒂克:长单词;
程序下载;
过程HttpWorkBegin(ASender:ToObject;AWorkMode:TWorkMode;AWorkCountMax:Int64);
过程HttpWork(ASender:ToObject;AWorkMode:TWorkMode;AWorkCount:Int64);
过程HttpWorkEnd(ASender:ToObject;AWorkMode:TWorkMode);
...
结束;
程序TSomeClass.下载;
变量
缓冲区:TNoPresizeFileStream;
HttpClient:TIdHttp;
开始
缓冲区:=TNoPresizeFileStream.Create('somefile.exe',fmCreate或fmShareDenyWrite);
尝试
HttpClient:=TIdHttp.Create(nil);
尝试
HttpClient.OnWorkBegin:=HttpWorkBegin;
HttpClient.OnWork:=HttpWork;
HttpClient.OnWorkEnd:=HttpWorkEnd;
HttpClient.Get('http://somewhere.com/somefile.exe“,缓冲区);//等到它完成
最后
HttpClient.Free;
结束;
最后
缓冲。免费;
结束;
结束;
过程TSomeClass.HttpWorkBegin(ASender:TObject;AWorkMode:TWorkMode;AWorkCountMax:Int64);
开始
如果工作模式为wmRead,则退出;
//根据需要初始化状态UI。。。
//
//如果TIdHTTP正在主线程中运行,请更新您的UI
//组件,然后调用窗体的
//Update()方法来执行重新绘制,或Application.ProcessMessages()
//处理其他UI操作,如按钮按下(用于
//例如,取消下载)。
//
//如果TIdHTTP正在工作线程中运行,请使用TIdNotify
//或TIdSync类来根据需要更新UI组件,以及
//让操作系统正常地分派重绘和其他消息。。。
TotalBytes:=AWorkCountMax;
LastWorkCount:=0;
LastTicks:=滴答声;
结束;
过程TSomeClass.HttpWork(ASender:TObject;AWorkMode:TWorkMode;AWorkCount:Int64);
变量
完成百分比:整数;
ElapsedMS:长单词;
ByTestTransferred:Int64;
字节数:Int64;
开始
如果工作模式为wmRead,则退出;
ElapsedMS:=GetTickDiff(LastTicks,Ticks);
如果ElapsedMS=0,则ElapsedMS:=1;//避免EDivByZero错误
如果TotalBytes>0,则
完成百分比:=(双倍(工作计数)/总字节)*100.0;
其他的
完成百分比:=0.0;
ByTestTransferred:=AWorkCount-LastWorkCount
type
TSomeClass = class(TSomething)
...
TotalBytes: In64;
LastWorkCount: Int64;
LastTicks: LongWord;
procedure Download;
procedure HttpWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
procedure HttpWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
procedure HttpWorkEnd(ASender: TObject; AWorkMode: TWorkMode);
...
end;
procedure TSomeClass.Download;
var
Buffer: TNoPresizeFileStream;
HttpClient: TIdHttp;
begin
Buffer := TNoPresizeFileStream.Create('somefile.exe', fmCreate or fmShareDenyWrite);
try
HttpClient := TIdHttp.Create(nil);
try
HttpClient.OnWorkBegin := HttpWorkBegin;
HttpClient.OnWork := HttpWork;
HttpClient.OnWorkEnd := HttpWorkEnd;
HttpClient.Get('http://somewhere.com/somefile.exe', Buffer); // wait until it is done
finally
HttpClient.Free;
end;
finally
Buffer.Free;
end;
end;
procedure TSomeClass.HttpWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
begin
if AWorkMode <> wmRead then Exit;
// initialize the status UI as needed...
//
// If TIdHTTP is running in the main thread, update your UI
// components directly as needed and then call the Form's
// Update() method to perform a repaint, or Application.ProcessMessages()
// to process other UI operations, like button presses (for
// cancelling the download, for instance).
//
// If TIdHTTP is running in a worker thread, use the TIdNotify
// or TIdSync class to update the UI components as needed, and
// let the OS dispatch repaints and other messages normally...
TotalBytes := AWorkCountMax;
LastWorkCount := 0;
LastTicks := Ticks;
end;
procedure TSomeClass.HttpWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
var
PercentDone: Integer;
ElapsedMS: LongWord;
BytesTransferred: Int64;
BytesPerSec: Int64;
begin
if AWorkMode <> wmRead then Exit;
ElapsedMS := GetTickDiff(LastTicks, Ticks);
if ElapsedMS = 0 then ElapsedMS := 1; // avoid EDivByZero error
if TotalBytes > 0 then
PercentDone := (Double(AWorkCount) / TotalBytes) * 100.0;
else
PercentDone := 0.0;
BytesTransferred := AWorkCount - LastWorkCount;
// using just BytesTransferred and ElapsedMS, you can calculate
// all kinds of speed stats - b/kb/mb/gm per sec/min/hr/day ...
BytesPerSec := (Double(BytesTransferred) * 1000) / ElapsedMS;
// update the status UI as needed...
LastWorkCount := AWorkCount;
LastTicks := Ticks;
end;
procedure TSomeClass.HttpWorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
if AWorkMode <> wmRead then Exit;
// finalize the status UI as needed...
end;
: 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;