使用Indy组件下载、暂停和恢复下载

yhived7q  于 2022-09-21  发布在  其他
关注(0)|答案(2)|浏览(175)

实际上,我正在使用TIdHTTP组件从互联网上下载文件。我想知道是否有可能使用此组件或其他Indy组件暂停和恢复下载。

这是我目前的代码,这可以下载一个文件(没有简历),但是。现在我想暂停下载关闭我的应用程序,当我的应用程序重新启动时,然后从最后保存的位置继续下载。

var
  Http: TIdHTTP;
  MS  : TMemoryStream;
begin
  Result:= True;
  Http  := TIdHTTP.Create(nil);
  MS    := TMemoryStream.Create;
  try

    try
      Http.OnWork:= HttpWork;//this event give me the actual progress of the download process
      Http.Head(Url);
      FSize := Http.Response.ContentLength;
      AddLog('Downloading File '+GetURLFilename(Url)+' - '+FormatFloat('#,',FSize)+' Bytes');
      Http.Get(Url, MS);
      MS.SaveToFile(LocalFile);
    except
      on E : Exception do
      Begin
       Result:=False;
       AddLog(E.Message);
      end;
    end;
  finally
    Http.Free;
    MS.Free;
  end;
end;
pobjuy32

pobjuy321#

下面的代码对我起作用了。它按块下载文件:

procedure Download(Url,LocalFile:String;
  WorkBegin:TWorkBeginEvent;Work:TWorkEvent;WorkEnd:TWorkEndEvent);
var
  Http: TIdHTTP;
  quit:Boolean;
  FLength,aRangeEnd:Integer;
begin
  Http  := TIdHTTP.Create(nil);
  fFileStream:=nil;
  try

    try
      Http.OnWork:= Work; 
      Http.OnWorkEnd := WorkEnd;

      Http.Head(Url);
      FLength := Http.Response.ContentLength;
      quit:=false;
      repeat

        if not FileExists(LocalFile) then begin
          fFileStream := TFileStream.Create(LocalFile, fmCreate);
        end
        else begin
          fFileStream := TFileStream.Create(LocalFile, fmOpenReadWrite);
          quit:= fFileStream.Size >= FLength;
          if not quit then
            fFileStream.Seek(Max(0, fFileStream.Size-4096), soFromBeginning);
        end;

        try
          aRangeEnd:=fFileStream.Size + 50000;

          if aRangeEnd < fLength then begin           
            Http.Request.Range := IntToStr(fFileStream.Position) + '-'+  IntToStr(aRangeEnd);
          end
          else begin
            Http.Request.Range := IntToStr(fFileStream.Position) + '-';
            quit:=true;
          end;

          Http.Get(Url, fFileStream);
        finally
          fFileStream.Free;
        end;
     until quit;
     Http.Disconnect;

    except
      on E : Exception do
      Begin
       //Result:=False;
       //AddLog(E.Message);
      end;
    end;
  finally
    Http.Free;
  end;
end;
xpszyzbs

xpszyzbs2#

也许HTTP Range标头可以在这里为您提供帮助。有关恢复HTTP下载的更多信息,请查看archive.org's copy of http://www.west-wind.com/Weblog/posts/244.aspx
(2004-02-07)几天前,留言板上的一个人问了一个有趣的问题,关于如何提供可恢复的HTTP下载。我对这个问题的第一个回答是,这是不可能的,因为HTTP是一种无状态协议,没有文件指针的概念,因此无法恢复HTTP下载。

然而,事实证明,HTTP1.1确实能够通过使用从客户端发送的http报头中的Range:报头来指定下载范围。您可以执行以下操作:

Range: 0-10000
Range: 100000-
Range: -100000

它下载前100000个字节、超过100000个字节或最后100000个字节的内容。有更多的组合,但前两个是对可恢复下载感兴趣的组合。

为了演示这一特性,我使用wwHTTP(在Web Connection/VFP中)使用HTTPGetEx将文件的第一个400k块下载到一个文件中,目的是模拟中止的下载。接下来,我执行第二个请求,以获取现有文件并下载其余文件:


# INCLUDE wconnect.h

CLEAR
CLOSE DATA
DO WCONNECT

LOCAL o as wwHTTP
lcDownloadedFile = "d:tempwwipstuff.zip"

***Simulate partial output

lcOutput = ""
Text=""
tnSize = 0
o = CREATEOBJECT("wwHTTP")
o.HttpConnect("www.west-wind.com")
? o.httpgetex("/files/wwipstuff.zip",@Text,@tnSize,"Range: bytes=0-400000"+CRLF,lcDownloadedFile)
o.Httpclose()

lcOutput = Text
? LEN(lcOutput)

***Figure out how much we downloaded

lnOpenAt = FILESIZE(lcDownloadedFile)

***Do a partial download starting at this byte count

Text=""
tnSize =0
o = CREATEOBJECT("wwHTTP")
o.HttpConnect("www.west-wind.com")
? o.httpgetex("/files/wwipstuff.zip",@Text,@tnSize,"Range: bytes=" + TRANSFORM(lnOpenAt) + "-" + CRLF)
o.Httpclose()

? LEN(Text)

***Read the existing partial download and append current download

lcOutput = FILETOSTR(lcDownloadedFile) + TEXT
? LEN(lcOutput)

STRTOFILE(lcOutput,lcDownloadedFile)

RETURN

请注意,此方法使用磁盘上的文件,因此您必须使用HTTPGetEx(带Web连接)。如果您愿意,第二次下载也可以下载到磁盘上,但如果您有多次中止,并且需要将它们拼凑在一起,事情就会变得棘手。在这种情况下,您可能希望跟踪每个文件并向其添加一个数字,然后在最后合并结果。

如果您使用WinInet下载到内存(这是wwHTTP在幕后使用的),您还可以尝试从临时Internet文件缓存中取出文件。虽然这是可行的,但我怀疑这个过程很快就会变得非常复杂,所以如果您计划提供恢复的能力,我强烈建议您使用上面的方法编写输出文件。

这里描述了有关WinInet的一些其他信息以及此方法使用它的一些要求:http://www.clevercomponents.com/articles/article015/resuming.asp

通过将Range标头添加到wwHTTP:WebRequest.Headers对象,可以对.Net的wwHTTP执行相同的操作。
(Randy Pearson)说你不知道服务器上的文件大小。例如,有没有办法找出这一点,这样你就可以知道要请求多少块?您会先发送Head请求,还是GET响应的Header也会告诉您总大小?

(Rick Strahl)您必须阅读Content-Length:头文件才能获得下载的文件大小。如果您正在恢复,这不应该有什么关系-您只需使用range:(ExistingSize)-来获取其余内容。对于大块的下载,您可以阅读内容长度,并且只下载前x个字节。这在wwHTTP中变得很棘手--您必须使用HTTPGetEx进行单独的调用,并将tnBufferSize参数设置为区块大小,以便在达到该大小后停止检索。

(兰迪·皮尔逊)跟进:看起来一个合规的服务器会发送足够的信息给你,让你知道大小。如果它提供数据块,它应该回复如下内容:

Content-Range: 0-10000/85432

因此,您可以(如果需要)提取它并在循环中使用它,以继续处理智能块请求。

有关同一主题的TIdHTTP相关讨论,还请查看https://forums.embarcadero.com/message.jspa?messageID=219481

(至少部分按照tfilestream.seek and offset confusion)

if FileExists(dstFile) then
begin
  Fs := TFileStream.Create(dstFile, fmOpenReadWrite);
  try
    Fs.Seek(Max(0, Fs.Size-1024), soFromBeginning);
    // alternatively:
    // Fs.Seek(-1024, soFromEnd);
    Http.Request.Range := IntToStr(Fs.Position) + '-';
    Http.Get(Url, Fs);
  finally
    Fs.Free;
  end;
end;

相关问题