You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Indy实现支持断点续传的文件下载?

解决Indy IdHTTP断点续传失效问题

核心逻辑

断点续传的关键是告诉服务器从已下载的位置继续传输,同时本地文件以追加模式写入,而不是覆盖。你之前调用IdHttp1.Disconnect()只是断开了连接,但恢复时没有向服务器传递续传位置的信息,导致重新从头下载。

具体实现步骤

1. 记录已下载字节数

暂停下载时,先获取本地已下载文件的大小(如果是边下载边写入,就是当前文件的实际字节数),将这个值保存到变量中,比如FDownloadedSize: Int64。

2. 恢复时设置Range请求头

重新发起下载请求前,给IdHTTP1.Request.Range赋值,格式为bytes=已下载大小-。例如已下载了5120字节,就设置为'bytes=5120-',告诉服务器从第5121字节开始传输。

3. 本地文件以追加模式打开

恢复下载时,不要创建新文件,而是用fmOpenWrite or fmShareDenyWrite or fmAppend模式打开本地文件,确保新下载的内容追加到已有内容末尾。

完整示例代码

unit DownloadDemo;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
  IdIOHandlerSocket, IdIOHandlerStack, IdSSLOpenSSL;

type
  TMainForm = class(TForm)
    IdHTTP1: TIdHTTP;
    btnStartResume: TButton;
    btnPause: TButton;
    edtFileURL: TEdit;
    edtSavePath: TEdit;
    procedure btnStartResumeClick(Sender: TObject);
    procedure btnPauseClick(Sender: TObject);
  private
    FDownloadStream: TFileStream;
    FDownloadedSize: Int64;
    FIsPaused: Boolean;
    procedure ExecuteDownload;
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.btnStartResumeClick(Sender: TObject);
begin
  if FIsPaused then
  begin
    // 恢复下载
    ExecuteDownload;
    btnStartResume.Caption := '开始下载';
    FIsPaused := False;
  end
  else
  begin
    // 首次下载或重置下载
    FDownloadedSize := 0;
    if FileExists(edtSavePath.Text) then
    begin
      // 读取已有文件大小作为续传起点
      var TempStream := TFileStream.Create(edtSavePath.Text, fmOpenRead or fmShareDenyWrite);
      FDownloadedSize := TempStream.Size;
      TempStream.Free;
    end;
    ExecuteDownload;
  end;
  btnPause.Enabled := True;
end;

procedure TMainForm.btnPauseClick(Sender: TObject);
begin
  // 确保文件流数据写入磁盘
  if Assigned(FDownloadStream) then
    FDownloadStream.Position := FDownloadStream.Size;
  // 断开连接暂停下载
  IdHTTP1.Disconnect;
  FreeAndNil(FDownloadStream);
  FIsPaused := True;
  btnStartResume.Caption := '恢复下载';
  btnPause.Enabled := False;
end;

procedure TMainForm.ExecuteDownload;
begin
  try
    if FDownloadedSize > 0 then
    begin
      // 设置续传请求头
      IdHTTP1.Request.Range := Format('bytes=%d-', [FDownloadedSize]);
      // 追加模式打开文件
      FDownloadStream := TFileStream.Create(edtSavePath.Text, fmOpenWrite or fmShareDenyWrite or fmAppend);
    end
    else
    begin
      // 首次下载,创建新文件
      FDownloadStream := TFileStream.Create(edtSavePath.Text, fmCreate or fmShareDenyWrite);
    end;

    // 执行下载
    IdHTTP1.Get(edtFileURL.Text, FDownloadStream);
    ShowMessage('下载完成');
    btnPause.Enabled := False;
  except
    on E: Exception do
    begin
      if E is EIdConnClosedGracefully then
      begin
        // 主动断开引发的异常,标记为暂停状态
        FIsPaused := True;
        btnStartResume.Caption := '恢复下载';
      end
      else
        ShowMessage('下载出错:' + E.Message);
    end;
  end;
end;

end.

关键注意事项

  • 提前验证服务器支持:可以先发送HEAD请求,检查响应头的Accept-Ranges字段是否为bytes,确认服务器支持断点续传。
  • 下载过程中不要随意修改文件流位置,避免数据写入异常。
  • 服务器返回206 Partial Content响应码时,说明续传成功;如果返回200 OK,则表示服务器不支持续传,会重新下载整个文件。

内容的提问来源于stack exchange,提问作者user10825637

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:54:38