Delphi 使用Indy下载文件时,从一开始就指定完整大小
我有这个delphi代码,基本上下载一个文件(使用delphi 2010+Indy 10.5.8 r4743),一切正常,除了当我下载100Mb(例如)时,Indy似乎分配了完整的大小(即立即创建一个包含100Mb虚拟内容(*)的文件),然后下载该文件 最后100MB被正确下载,但由于下载过程是在后台使用隐藏的可执行文件完成的,因此我的代码基于临时文件大小来更新主UIDelphi 使用Indy下载文件时,从一开始就指定完整大小,delphi,download,delphi-2010,indy,indy10,Delphi,Download,Delphi 2010,Indy,Indy10,我有这个delphi代码,基本上下载一个文件(使用delphi 2010+Indy 10.5.8 r4743),一切正常,除了当我下载100Mb(例如)时,Indy似乎分配了完整的大小(即立即创建一个包含100Mb虚拟内容(*)的文件),然后下载该文件 最后100MB被正确下载,但由于下载过程是在后台使用隐藏的可执行文件完成的,因此我的代码基于临时文件大小来更新主UI with IdHTTP do begin if FileExists(LocalFile) then
with IdHTTP do
begin
if FileExists(LocalFile) then
iLength := FileSize2(LocalFile)
else
iLength := 0;
DoExit := False;
try
try
repeat
if ExitApp then
Exit;
if Not FileExists(LocalFile) then
AFileStream := TFileStream.Create(LocalFile, fmCreate)
else
begin
// File already exist, resume download
AFileStream := TFileStream.Create(LocalFile, fmOpenReadWrite);
DoExit := (AFileStream.Size >= iLength);
if (Not DoExit) then
AFileStream.Seek(Max(0, AFileStream.Size - 4096), soFromBeginning);
end;
iRangeEnd := AFileStream.Size + 50000;
if (iRangeEnd < iLength) then
Request.Range := IntToStr(AFileStream.Position) + '-' + IntToStr(iRangeEnd)
else
begin
Request.Range := IntToStr(AFileStream.Position) + '-';
DoExit := True;
end;
PostTime := Now;
Get(TheURL, AFileStream);
IsError := Not (ResponseCode in [200, 206]);
until DoExit;
Disconnect;
except
IsError := True;
end; // try/except
finally
FreeAndNil(AFileStream);
end; // try/finally
end; // with
使用IdHTTP-do
开始
如果文件存在(LocalFile),则
iLength:=文件大小2(本地文件)
其他的
i长度:=0;
DoExit:=假;
尝试
尝试
重复
如果退出,那么
出口
如果文件不存在(LocalFile),则
AFileStream:=TFileStream.Create(LocalFile,fmCreate)
其他的
开始
//文件已存在,请继续下载
AFileStream:=TFileStream.Create(LocalFile,fmOpenReadWrite);
DoExit:=(AFileStream.Size>=ilelength);
如果(不是DoExit)那么
Seek(最大值(0,AFileStream.Size-4096),从开始到结束);
结束;
iRangeEnd:=AFileStream.Size+50000;
如果(iRangeEnd
我的问题是有没有办法避免印地的这种行为?我知道我可以使用OnWork事件,但是我需要跟踪文件名
理想情况下,我也希望避免IPC(有点过分了+我不想使用它,比如说每秒,对于多次下载,我非常喜欢使用文件大小作为下载进度的指示,因为它在更新UI时提供了更多的自由度)
(*)我假设它是虚拟内容,因为我需要60-100秒的当前internet连接速度才能真正获取文件是,
TIdHTTP
根据HTTP响应头预先分配完整文件大小(如果它提前知道大小)。这是一种优化技术。预分配文件可避免在写入较大文件时产生不必要的文件系统开销,因为文件不必随着时间的推移而不断增长,从而在HDD上寻找可用扇区,从而减慢写入过程。目前没有办法禁用预分配,这是Indy内部的硬编码行为。因此,依赖文件的实际大小作为进度指示器对您来说是行不通的。你必须将实际进度信息从后台应用程序传送到主应用程序。谢谢你,雷米……虽然我理解这一决定背后的原因,但这使得暂停/恢复下载变得很困难(如果不是不可能的话),因为我无法知道恢复字节/偏移量。我意识到这是一个不同的问题(源于原始问题),但我想知道是否有解决方案?您必须使用OnWork…
事件来跟踪实际进度,然后在下载中断时将磁盘上的文件截断为最后已知的大小。TIdHTTP
不会预先分配文件的唯一时间是使用chunked
传输编码发送数据,在这种情况下,TIdHTTP
不会提前被告知文件大小(因为服务器本身可能不知道)。Indy的源代码中已经有一条TODO注释,可以将预分配作为可选功能,但是没有关于何时实现的ETA。谢谢你,Remy,是的,这就是我正在做的,我正在考虑编写*.progress文件,以便在硬崩溃后恢复,希望这对meRemy有效,我想(我将下载信息存储在数据库中),唯一的问题是,当恢复时(崩溃后),a工作计数
反映当前会话字节计数,但它不考虑以前下载的字节(在应用程序崩溃之前)。是否有办法在OnWork()中获取总的下载字节位置
来自Indy本身的事件(即TIdHTTP(Sender).CurrentPosition
或类似的东西)?因此在主文件旁边写一个“filename.zip.progress”文本文件。:-)是的,这正是我所做的!