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

Sal*_*dor 5 delphi indy

实际上我正在使用TIdHTTP组件从互联网上下载文件.我想知道是否可能暂停并使用此组件恢复下载o也许是另一个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;
Run Code Online (Sandbox Code Playgroud)

Dan*_*iCE 6

以下代码对我有用.它按块下载文件:

procedure Download(Url,LocalFile:String;
  WorkBegin:TWorkBeginEvent;Work:TWorkEvent;WorkEnd:TWorkEndEvent);
var
  Http: TIdHTTP;
  exit: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;
      exit:=false;
      repeat

        if not FileExists(LocalFile) then begin
          fFileStream := TFileStream.Create(LocalFile, fmCreate);
        end
        else begin
          fFileStream := TFileStream.Create(LocalFile, fmOpenReadWrite);
          exit:= fFileStream.Size >= FLength;
          if not exit 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) + '-';
            exit:=true;
          end;

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

    except
      on E : Exception do
      Begin
       //Result:=False;
       //AddLog(E.Message);
      end;
    end;
  finally
    Http.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)


K.S*_*ell 3

也许 HTTP RANGE 标头可以在这里帮助您。请查看archive.org 的 http://www.west-wind.com/Weblog/posts/244.aspx 副本,了解有关恢复 HTTP 下载的更多信息:

( 2004-02-07 ) 几天前,留言板上有人问了一个有趣的问题,关于如何提供可断点续传的HTTP 下载。我对这个问题的第一反应是,这是不可能的,因为 HTTP 是一种无状态协议,没有文件指针的概念,因此无法恢复 HTTP 下载。

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

Range: 0-10000
Range: 100000-
Range: -100000
Run Code Online (Sandbox Code Playgroud)

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

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

#INCLUDE wconnect.h
CLEAR
CLOSE DATA
DO WCONNECT

LOCAL o as wwHTTP
lcDownloadedFile = "d:\temp\wwipstuff.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
Run Code Online (Sandbox Code Playgroud)

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

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

有关 WinInet 的一些附加信息以及使用此方法的一些要求如下所述: http: //www.clevercomponents.com/articles/article015/resuming.asp

通过将 Range 标头添加到 wwHTTP:WebRequest.Headers 对象,可以对 .Net 的 wwHTTP 完成相同的操作。

( Randy Pearson ) 假设您不知道服务器上的文件大小是多少。有没有办法找到这个问题,例如,您可以知道要请求多少块?您会先发送 HEAD 请求,还是 GET 响应的标头也告诉您总大小?

( Rick Strahl ) 您必须读取 Content-Length: 标头才能获取下载文件的大小。如果您要恢复,这应该不重要 - 您只需使用 Range: (existingsize) - 即可获得其余内容。对于大块下载,您可以读取内容长度并仅下载前 x 个字节。对于 wwHTTP,这会变得很棘手 - 您必须使用 HTTPGetEx 进行单独的调用,并将 tnBufferSize 参数设置为要检索的块大小,以使其在达到大小后停止。

( Randy Pearson ) 后续: 看起来兼容的服务器会向您发送足够的信息来了解大小。如果它提供块,它应该回复如下内容:

Content-Range: 0-10000/85432
Run Code Online (Sandbox Code Playgroud)

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

另请参阅此处https://forums.embarcadero.com/message.jspa?messageID=219481,了解同一主题的 TIdHTTP 相关讨论:

至少部分按照 tfilestream.seek 和偏移量混淆

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;
Run Code Online (Sandbox Code Playgroud)