unit Unit2;


interface

uses
  Windows, Messages, SysUtils, Classes, Forms, Controls, Graphics, StdCtrls,
  IdCookieManager, IdHTTP, IdMultipartFormData, IdGlobal, 
  StrUtils, Activex, ComCtrls, ShellApi;
type
  TUploadFile = class(TThread)
    constructor Create(Url: String; FileName: String); overload;
  protected
    procedure Execute; override;
  private
    IsStop: Boolean;
    IsPause: Boolean;
    PrUrl: String;
    PrFileName: String;
  public
    function UploadStream(FileName: String; Size, Position, Block: Int64; Buffer: TObject): String;
    procedure UploadFile();
    procedure Pause;
    procedure Cancel;
  end;
var
  GLOBAL_EXIT: Boolean;
  GLOBAL_POSITION: Int64;
  GLOBAL_TASK: TUploadFile;

implementation
uses
  Unit1;

constructor TUploadFile.Create(Url: String; FileName: String);
begin
  PrUrl:= Url;
  PrFileName:= FileName;
  inherited Create(true); // 挂起线程
end;

procedure TUploadFile.Execute;
begin
  CoInitialize(nil);
  UploadFile;
  CoUninitialize;
end;

procedure TUploadFile.UploadFile();
  function GetFileSizeString(FileSize: Int64):String;
  begin
    try
      if (FileSize>(1024*1024*1000)) then Result:= format('%f',[(FileSize / (1024*1024*1024))]) + 'GB'
      else
        if (FileSize>(1024*1000)) then Result:= format('%f',[(FileSize / (1024*1024))]) + 'MB'
        else
          if FileSize>1000 then Result:= format('%f',[(FileSize / (1024))]) + 'KB'
          else Result:= format('%f',[FileSize / 1.00]) + 'B';
    except
      Result:= '0 B';
    end;
  end;
var
  vResult: String;
  vPosition, vBlock: Int64;
  vFile: TFileStream;
  vStream: TMemoryStream;
begin
  vResult:= '0';
  vPosition:= GLOBAL_POSITION;
  if not FileExists(PrFileName) then begin
    Form1.Button1.Enabled:= False;
    Form1.Button2.Enabled:= False;
    Form1.Button3.Enabled:= True;
    Form1.Button4.Enabled:= False;
    Form1.ListBox1.Items.Add('上传文件错误，文件不存在');
    Exit;
  end;
  try
    vFile:= TFileStream.Create(PrFileName, fmOpenRead);
  except
    on EInOutError do begin
      Form1.Button1.Enabled:= False;
      Form1.Button2.Enabled:= False;
      Form1.Button3.Enabled:= True;
      Form1.Button4.Enabled:= False;
      Form1.ListBox1.Items.Add('上传文件错误，文件正在使用中');
      Exit;
    end;
  end;
  while (vResult='0') and (vPosition<vFile.Size) do
  begin
    if GLOBAL_EXIT or Self.IsStop then begin
      if not GLOBAL_EXIT then
        if Self.IsPause then Form1.ListBox1.Items.Add('上传文件被暂停')
        else Form1.ListBox1.Items.Add('上传文件被终止');
      if not Self.IsPause then GLOBAL_POSITION:= 0;
      vFile.Free;
      Self.Terminate;  //  如果系统已经退出，则线程自动退出
      Exit;
    end;
    vFile.Position:= vPosition;
    if vFile.Size - vPosition > 102400 then vBlock:= 102400
    else vBlock:= vFile.Size - vPosition;
    vStream:= TMemoryStream.Create;
    vStream.SetSize(vBlock);
    vStream.Position:=0;
    vStream.CopyFrom(vFile, vBlock);
    vResult:= UploadStream(PrFileName, vFile.Size, vPosition, vBlock, vStream);
    if vResult='0' then begin
      GLOBAL_POSITION:= GLOBAL_POSITION + vBlock;
      vPosition:= vPosition + vBlock;
      Form1.ListBox1.Items.Add('上传文件中...已上传['+GetFileSizeString(vPosition)+']');
      Form1.ListBox1.ScrollBy(0, 10000);
    end;
    vStream.Free;
    Sleep(10);
  end;   
  if vPosition>=vFile.Size then
    Form1.ListBox1.Items.Add('文件上传已成功')
  else
    Form1.ListBox1.Items.Add('文件上传未成功');
  Form1.ListBox1.ScrollBy(0, 10000);
  Form1.Button1.Enabled:= False;
  Form1.Button2.Enabled:= False;
  Form1.Button3.Enabled:= True;
  Form1.Button4.Enabled:= False;
  vFile.Free;
end;

function TUploadFile.UploadStream(FileName: String; Size, Position, Block: Int64; Buffer: TObject): String;
var                
  vEnd: Boolean;
  vIdHttp: Tidhttp;
  vResponse: string;
  vMutPartForm: TIdMultiPartFormDataStream;
begin
  vEnd:= False;
  while not vEnd do begin
    vResponse:= '';
    vMutPartForm := TIdMultiPartFormDataStream.Create;
    vMutPartForm.AddFormField('Command', 'Upload');
    vMutPartForm.AddFormField('Size', IntToStr(Size));
    vMutPartForm.AddFormField('Position', IntToStr(Position));
    vMutPartForm.AddFormField('Block', IntToStr(Block));
    vMutPartForm.AddFormField('FileData', AnsiToUTF8('filename="'+FileName+'"'));
    vMutPartForm.AddObject('FileData', GetMIMETypeFromFile(FileName), Buffer, AnsiToUTF8(FileName));
    vIdHttp:= Tidhttp.Create(nil);
    vIdHttp.AllowCookies:= true;
    try
      try
        vEnd:= True;
        vResponse:= vIdHttp.Post(PrUrl, vMutPartForm);
      except
        Case vIdHttp.ResponseCode of
          500: begin
              vResponse:= '10';
              vEnd:= True;
            end;
          else begin
            if Application.MessageBox('上传文件出错，点击“是”重新上传，点击“否”跳转至下一个。','断点续传[上传]', MB_YESNO or MB_ICONQUESTION or MB_DEFBUTTON2)= IDYES then begin
              vEnd:= False;
            end
            else begin
              vEnd:= True;
              vResponse:= '9';
            end;
          end;
        end;
      end;
    finally
      vMutPartForm.Free;
      vIdHttp.Free;
    end;
  end;
  Result:= vResponse;
end;
//  ----------------------------------------------------------------------------
//  说明：暂停当前线程
//  ----------------------------------------------------------------------------
procedure TUploadFile.Pause;
begin
  Self.IsPause:= True; 
  Self.IsStop:= True;
end;
//  ----------------------------------------------------------------------------
//  说明：终止当前线程
//  ----------------------------------------------------------------------------
procedure TUploadFile.Cancel;
begin
  Self.IsPause:= False; 
  Self.IsStop:= True;
end;

end.

