{******************************************************************************
文件名称: uWnDownLoadHelper.pas
文件功能: 断点续传下载线程单元
作者 : enli
--------------------------------------------------------------------------------}
文件名称: uWnDownLoadHelper.pas
文件功能: 断点续传下载线程单元
作者 : enli
--------------------------------------------------------------------------------}
unit uWnDownLoadHelper;
interface
uses
IdHTTP, IdAuthentication, IdHeaderList, IniFiles, md5,
SysUtils, IdAuthenticationSSPI, IdAuthenticationDigest, Classes, IdException,
IdSocks, IdIOHandlerSocket, DateUtils, IdComponent, Forms,ucchttpClient;
const
S_TMP_POSTFIX = '.tmp';
S_INI_POSTFIX = '.sni';
type
TWnDownloadProgress = procedure(APosition,ACount: Int64) of object;
// 代理设置结构
TWnProxySetting = packed record
FIsProxyEnabled: Boolean;
FSocksVersion: TSocksVersion;
FProxyHost: string;
FProxyPort: Word;
FAuthUserName: string;
FAuthPassword: string;
FAuthDomain:string;
end;
PWnProxySetting = ^TWnProxySetting;
TWnDownLoadThread = class(TThread)
private
FHttp: TCCHTTPClient;
FProxy: TWnProxySetting;
FTarget: string;
FSaveFile: string;
FTempFile: string;
FProgress: TWnDownloadProgress;
FCurrentFileSize,FFileSize : Int64;
FSaveLocation: string;
FOnLog: TDolog;
FWarningMsg: string;
FReLoad: Boolean;
procedure SetProxy(const Value: PWnProxySetting);
function GetProxy :PWnProxySetting;
procedure SetHttpProxy;
procedure SetTarget(const Value: string);
procedure SetProgress(const Value: TWnDownloadProgress);
procedure DoBeginWork(Sender: TObject;const APos,ACount: Int64);
procedure DoWork(Sender: TObject;const AWork:Int64);
procedure DoEndWork(Sender: TObject);
procedure DoUpdateUI;
procedure SetSaveLocation(const Value: string);
procedure SaveIniFile;
procedure DelIniFile;
procedure DoLog(const AMsg:string);
procedure DoSycLog;
function GetTempFile:string;
procedure SetOnLog(const Value: TDolog);
procedure SetReLoad(const Value: Boolean);
public
procedure Execute; override;
constructor Create;
destructor Destroy; override;
class procedure chunkedConvertToFile(const ASource,ADestination:string);
property PProxy:PWnProxySetting read GetProxy write SetProxy;
property Target:string read FTarget write SetTarget;
property SaveLocation :string read FSaveLocation write SetSaveLocation;
property Progress:TWnDownloadProgress read FProgress write SetProgress;
property ReLoad:Boolean read FReLoad write SetReLoad;
property OnLog: TDolog read FOnLog write SetOnLog;
end;
procedure DownLoadFile(const AUrl,ASaveFile:string;AProxy:PWnProxySetting;AProgress:TWnDownloadProgress;ALog:TDolog;AReLoad:Boolean);
implementation
procedure DownLoadFile(const AUrl,ASaveFile:string;AProxy:PWnProxySetting;AProgress:TWnDownloadProgress;ALog:TDolog;AReLoad:Boolean);
var
LThread: TWnDownLoadThread;
begin
LThread := TWnDownLoadThread.Create;
LThread.ReLoad := AReLoad;
LThread.Target := AUrl;
LThread.SaveLocation := ASaveFile;
LThread.PProxy := AProxy;
LThread.Progress :=AProgress;
LThread.OnLog := ALog;
LThread.Resume;
end;
{ TWnDownLoadThread }
class procedure TWnDownLoadThread.chunkedConvertToFile(const ASource,
ADestination: string);
var
LSStream,LDStream: TFileStream;
LBuff: Byte;
LFlag: Boolean;
LTemp : string;
I,LCount : Integer;
begin
if not FileExists(ASource) then Exit;
if FileExists(ADestination) then Exit;
LSStream := TFileStream.Create(ASource,fmOpenRead );
LDStream := TFileStream.Create(ADestination,fmCreate);
try
LSStream.Seek(0,0);
LFlag := True;
I := 0;
while LFlag do
begin
LSStream.Read(LBuff,SizeOf(Byte));
Inc(I);
if (LBuff = $0A) and (I>2) and (LTemp[I-1] = #$0D) then begin
LCount := StrToIntDef('$'+trim(LTemp),1);
if LCount = 1 then
begin
LCount := 0;
Break;
//raise 异常
end;
if LCount = 0 then
LFlag := False
else
begin
LDStream.CopyFrom(LSStream,LCount);
I := 0;
LTemp := '';
end;
end
else
LTemp := LTemp + Char(LBuff);
end;
finally
FreeAndNil(LSStream);
FreeAndNil(LDStream);
end;
end;
constructor TWnDownLoadThread.Create;
begin
inherited Create(True);
FreeOnTerminate := True;
FTarget := '';
FSaveFile := '';
//New(FProxy);
end;
procedure TWnDownLoadThread.DelIniFile;
begin
DeleteFile(FSaveLocation + FTempFile+S_INI_POSTFIX);
end;
destructor TWnDownLoadThread.Destroy;
begin
//Dispose(FProxy);
inherited;
end;
procedure TWnDownLoadThread.DoBeginWork(Sender: TObject;
const APos,ACount: Int64);
begin
FFileSize := ACount;
FCurrentFileSize := APos ;
SaveIniFile;
Synchronize(DoUpdateUI);
end;
procedure TWnDownLoadThread.DoEndWork(Sender: TObject);
begin
FCurrentFileSize := FFileSize;
Synchronize(DoUpdateUI);
end;
procedure TWnDownLoadThread.DoLog(const AMsg: string);
begin
if Assigned(FOnlog) then
begin
///DoDownLoadLog(AMsg);
FWarningMsg:= AMsg;
Synchronize(DoSycLog);
end;
end;
procedure TWnDownLoadThread.DoSycLog;
begin
FOnlog(FWarningMsg);
end;
procedure TWnDownLoadThread.DoUpdateUI;
begin
if Assigned(FProgress) then
FProgress(FCurrentFileSize,FFileSize);
end;
procedure TWnDownLoadThread.DoWork(Sender: TObject; const AWork: Int64);
begin
FCurrentFileSize := FCurrentFileSize+ AWork;
Synchronize(DoUpdateUI);
end;
procedure TWnDownLoadThread.Execute;
var
LDoc,
LHost,
LPath,
LProto,
LPort,
LBookmark: string;
begin
if Length(FTarget) = 0 then Exit;
if Length(FSaveLocation) = 0 then Exit;
FHttp := TCCHTTPClient.Create(nil);
try
FHttp.IOHandler := TIdIOHandlerSocket.Create(FHttp);
FHttp.Socket.SocksInfo := TIdSocksInfo.Create(FHttp);
FHttp.ProtocolVersion := uCCHTTPClient.pv1_1;
SetHttpProxy;
FHttp.OnDownloadBegin := DoBeginWork;
FHttp.OnDownload := DoWork;
FHttp.OnDownloadEnd := DoEndWork;
FHttp.OnLog := DoLog;
FHttp.ParseURI(FTarget, LProto, LHost, LPath, LDoc, LPort, LBookmark);
FSaveFile := LDoc;
FTempFile := GetTempFile+'.'+LDoc;
if FReLoad and FileExists(FSaveLocation + FTempFile+S_TMP_POSTFIX) then
DeleteFile(FSaveLocation + FTempFile+S_TMP_POSTFIX);
DoLog('下载开始请求');
try
FHttp.DownLoad(FTarget,FSaveLocation + FTempFile+S_TMP_POSTFIX);
except
on E:Exception do
DoLog(e.Message);
end;
if FileExists(FSaveLocation + FTempFile+S_INI_POSTFIX) then
begin
if FileExists(FSaveLocation + LDoc) then
DeleteFile(FSaveLocation + LDoc);
if FHttp.Response.TransferEncoding = 'chunked' then
begin
chunkedConvertToFile(FSaveLocation + FTempFile+S_TMP_POSTFIX,FSaveLocation + LDoc);
DeleteFile(FSaveLocation + FTempFile+S_TMP_POSTFIX);
end
else
RenameFile(FSaveLocation + FTempFile+S_TMP_POSTFIX,FSaveLocation + LDoc);
DelIniFile;
end
else
DeleteFile(FSaveLocation + FTempFile+S_TMP_POSTFIX);
finally
FreeAndNil(FHttp);
DoLog('下载结束');
end;
end;
function TWnDownLoadThread.GetProxy: PWnProxySetting;
begin
Result := @FProxy
end;
function TWnDownLoadThread.GetTempFile: string;
var
Ltemp: string;
begin
Ltemp := MD5Print(MD5String(FTarget));
//Ltemp := copy(Ltemp, 2, length(Ltemp) - 2);
Result := StringReplace(Ltemp,'-','.',[rfReplaceAll] );
end;
procedure TWnDownLoadThread.SaveIniFile;
var
LIni:TIniFile;
begin
LIni := TIniFile.Create(FSaveLocation + FTempFile+S_INI_POSTFIX);
try
LIni.WriteString('Setup','URL',FTarget);
LIni.WriteString('Setup','SaveLocation',FSaveLocation);
LIni.WriteString('Setup','SaveFile',FSaveFile);
LIni.WriteString('Setup','TempFile',FTempFile);
LIni.WriteString('Setup','FileSize',FloatToStr(FFileSize));
finally
LIni.Free;
end;
end;
procedure TWnDownLoadThread.SetHttpProxy;
begin
if not Assigned(FHttp) then Exit;
with FProxy do
if FIsProxyEnabled then
begin
FHttp.Socket.SocksInfo.Version := FSocksVersion;
FHttp.Socket.SocksInfo.Host := FProxyHost;
FHttp.Socket.SocksInfo.Port := FProxyPort;
if FHttp.Socket.SocksInfo.Username <> '' then
FHttp.Socket.SocksInfo.Authentication := saUsernamePassword
else
FHttp.Socket.SocksInfo.Authentication := saNoAuthentication;
FHttp.AuthUsername := FAuthUserName;
FHttp.AuthPassword := FAuthPassword;
FHttp.AuthDomain := FAuthDomain;
FHttp.ProxyHost := FProxyHost;
FHttp.ProxyPort := FProxyPort;
end;
end;
procedure TWnDownLoadThread.SetOnLog(const Value: TDolog);
begin
FOnLog := Value;
end;
procedure TWnDownLoadThread.SetProgress(const Value: TWnDownloadProgress);
begin
FProgress := Value;
end;
procedure TWnDownLoadThread.SetProxy(const Value: PWnProxySetting);
begin
//New(FProxy);
FProxy.FIsProxyEnabled :=Value^.FIsProxyEnabled;
FProxy.FSocksVersion := Value^.FSocksVersion;
FProxy.FProxyHost := Value^.FProxyHost;
FProxy.FProxyPort := Value^.FProxyPort;
FProxy.FAuthUserName := Value^.FAuthUserName;
FProxy.FAuthPassword := Value^.FAuthPassword;
FProxy.FAuthDomain := Value^.FAuthDomain;
FProxy.FProxyHost := Value^.FProxyHost;
FProxy.FProxyPort := Value^.FProxyPort;
end;
procedure TWnDownLoadThread.SetReLoad(const Value: Boolean);
begin
FReLoad := Value;
end;
procedure TWnDownLoadThread.SetSaveLocation(const Value: string);
begin
FSaveLocation := Value;
if FSaveLocation[Length(FSaveLocation)] <> '\' then
FSaveLocation := FSaveLocation +'\';
end;
procedure TWnDownLoadThread.SetTarget(const Value: string);
begin
if Length(Value) = 0 then Exit;
if UpperCase(Copy(Value,1,7)) <> 'HTTP://' then Exit;
FTarget := Value;
end;
end.
interface
uses
IdHTTP, IdAuthentication, IdHeaderList, IniFiles, md5,
SysUtils, IdAuthenticationSSPI, IdAuthenticationDigest, Classes, IdException,
IdSocks, IdIOHandlerSocket, DateUtils, IdComponent, Forms,ucchttpClient;
const
S_TMP_POSTFIX = '.tmp';
S_INI_POSTFIX = '.sni';
type
TWnDownloadProgress = procedure(APosition,ACount: Int64) of object;
// 代理设置结构
TWnProxySetting = packed record
FIsProxyEnabled: Boolean;
FSocksVersion: TSocksVersion;
FProxyHost: string;
FProxyPort: Word;
FAuthUserName: string;
FAuthPassword: string;
FAuthDomain:string;
end;
PWnProxySetting = ^TWnProxySetting;
TWnDownLoadThread = class(TThread)
private
FHttp: TCCHTTPClient;
FProxy: TWnProxySetting;
FTarget: string;
FSaveFile: string;
FTempFile: string;
FProgress: TWnDownloadProgress;
FCurrentFileSize,FFileSize : Int64;
FSaveLocation: string;
FOnLog: TDolog;
FWarningMsg: string;
FReLoad: Boolean;
procedure SetProxy(const Value: PWnProxySetting);
function GetProxy :PWnProxySetting;
procedure SetHttpProxy;
procedure SetTarget(const Value: string);
procedure SetProgress(const Value: TWnDownloadProgress);
procedure DoBeginWork(Sender: TObject;const APos,ACount: Int64);
procedure DoWork(Sender: TObject;const AWork:Int64);
procedure DoEndWork(Sender: TObject);
procedure DoUpdateUI;
procedure SetSaveLocation(const Value: string);
procedure SaveIniFile;
procedure DelIniFile;
procedure DoLog(const AMsg:string);
procedure DoSycLog;
function GetTempFile:string;
procedure SetOnLog(const Value: TDolog);
procedure SetReLoad(const Value: Boolean);
public
procedure Execute; override;
constructor Create;
destructor Destroy; override;
class procedure chunkedConvertToFile(const ASource,ADestination:string);
property PProxy:PWnProxySetting read GetProxy write SetProxy;
property Target:string read FTarget write SetTarget;
property SaveLocation :string read FSaveLocation write SetSaveLocation;
property Progress:TWnDownloadProgress read FProgress write SetProgress;
property ReLoad:Boolean read FReLoad write SetReLoad;
property OnLog: TDolog read FOnLog write SetOnLog;
end;
procedure DownLoadFile(const AUrl,ASaveFile:string;AProxy:PWnProxySetting;AProgress:TWnDownloadProgress;ALog:TDolog;AReLoad:Boolean);
implementation
procedure DownLoadFile(const AUrl,ASaveFile:string;AProxy:PWnProxySetting;AProgress:TWnDownloadProgress;ALog:TDolog;AReLoad:Boolean);
var
LThread: TWnDownLoadThread;
begin
LThread := TWnDownLoadThread.Create;
LThread.ReLoad := AReLoad;
LThread.Target := AUrl;
LThread.SaveLocation := ASaveFile;
LThread.PProxy := AProxy;
LThread.Progress :=AProgress;
LThread.OnLog := ALog;
LThread.Resume;
end;
{ TWnDownLoadThread }
class procedure TWnDownLoadThread.chunkedConvertToFile(const ASource,
ADestination: string);
var
LSStream,LDStream: TFileStream;
LBuff: Byte;
LFlag: Boolean;
LTemp : string;
I,LCount : Integer;
begin
if not FileExists(ASource) then Exit;
if FileExists(ADestination) then Exit;
LSStream := TFileStream.Create(ASource,fmOpenRead );
LDStream := TFileStream.Create(ADestination,fmCreate);
try
LSStream.Seek(0,0);
LFlag := True;
I := 0;
while LFlag do
begin
LSStream.Read(LBuff,SizeOf(Byte));
Inc(I);
if (LBuff = $0A) and (I>2) and (LTemp[I-1] = #$0D) then begin
LCount := StrToIntDef('$'+trim(LTemp),1);
if LCount = 1 then
begin
LCount := 0;
Break;
//raise 异常
end;
if LCount = 0 then
LFlag := False
else
begin
LDStream.CopyFrom(LSStream,LCount);
I := 0;
LTemp := '';
end;
end
else
LTemp := LTemp + Char(LBuff);
end;
finally
FreeAndNil(LSStream);
FreeAndNil(LDStream);
end;
end;
constructor TWnDownLoadThread.Create;
begin
inherited Create(True);
FreeOnTerminate := True;
FTarget := '';
FSaveFile := '';
//New(FProxy);
end;
procedure TWnDownLoadThread.DelIniFile;
begin
DeleteFile(FSaveLocation + FTempFile+S_INI_POSTFIX);
end;
destructor TWnDownLoadThread.Destroy;
begin
//Dispose(FProxy);
inherited;
end;
procedure TWnDownLoadThread.DoBeginWork(Sender: TObject;
const APos,ACount: Int64);
begin
FFileSize := ACount;
FCurrentFileSize := APos ;
SaveIniFile;
Synchronize(DoUpdateUI);
end;
procedure TWnDownLoadThread.DoEndWork(Sender: TObject);
begin
FCurrentFileSize := FFileSize;
Synchronize(DoUpdateUI);
end;
procedure TWnDownLoadThread.DoLog(const AMsg: string);
begin
if Assigned(FOnlog) then
begin
///DoDownLoadLog(AMsg);
FWarningMsg:= AMsg;
Synchronize(DoSycLog);
end;
end;
procedure TWnDownLoadThread.DoSycLog;
begin
FOnlog(FWarningMsg);
end;
procedure TWnDownLoadThread.DoUpdateUI;
begin
if Assigned(FProgress) then
FProgress(FCurrentFileSize,FFileSize);
end;
procedure TWnDownLoadThread.DoWork(Sender: TObject; const AWork: Int64);
begin
FCurrentFileSize := FCurrentFileSize+ AWork;
Synchronize(DoUpdateUI);
end;
procedure TWnDownLoadThread.Execute;
var
LDoc,
LHost,
LPath,
LProto,
LPort,
LBookmark: string;
begin
if Length(FTarget) = 0 then Exit;
if Length(FSaveLocation) = 0 then Exit;
FHttp := TCCHTTPClient.Create(nil);
try
FHttp.IOHandler := TIdIOHandlerSocket.Create(FHttp);
FHttp.Socket.SocksInfo := TIdSocksInfo.Create(FHttp);
FHttp.ProtocolVersion := uCCHTTPClient.pv1_1;
SetHttpProxy;
FHttp.OnDownloadBegin := DoBeginWork;
FHttp.OnDownload := DoWork;
FHttp.OnDownloadEnd := DoEndWork;
FHttp.OnLog := DoLog;
FHttp.ParseURI(FTarget, LProto, LHost, LPath, LDoc, LPort, LBookmark);
FSaveFile := LDoc;
FTempFile := GetTempFile+'.'+LDoc;
if FReLoad and FileExists(FSaveLocation + FTempFile+S_TMP_POSTFIX) then
DeleteFile(FSaveLocation + FTempFile+S_TMP_POSTFIX);
DoLog('下载开始请求');
try
FHttp.DownLoad(FTarget,FSaveLocation + FTempFile+S_TMP_POSTFIX);
except
on E:Exception do
DoLog(e.Message);
end;
if FileExists(FSaveLocation + FTempFile+S_INI_POSTFIX) then
begin
if FileExists(FSaveLocation + LDoc) then
DeleteFile(FSaveLocation + LDoc);
if FHttp.Response.TransferEncoding = 'chunked' then
begin
chunkedConvertToFile(FSaveLocation + FTempFile+S_TMP_POSTFIX,FSaveLocation + LDoc);
DeleteFile(FSaveLocation + FTempFile+S_TMP_POSTFIX);
end
else
RenameFile(FSaveLocation + FTempFile+S_TMP_POSTFIX,FSaveLocation + LDoc);
DelIniFile;
end
else
DeleteFile(FSaveLocation + FTempFile+S_TMP_POSTFIX);
finally
FreeAndNil(FHttp);
DoLog('下载结束');
end;
end;
function TWnDownLoadThread.GetProxy: PWnProxySetting;
begin
Result := @FProxy
end;
function TWnDownLoadThread.GetTempFile: string;
var
Ltemp: string;
begin
Ltemp := MD5Print(MD5String(FTarget));
//Ltemp := copy(Ltemp, 2, length(Ltemp) - 2);
Result := StringReplace(Ltemp,'-','.',[rfReplaceAll] );
end;
procedure TWnDownLoadThread.SaveIniFile;
var
LIni:TIniFile;
begin
LIni := TIniFile.Create(FSaveLocation + FTempFile+S_INI_POSTFIX);
try
LIni.WriteString('Setup','URL',FTarget);
LIni.WriteString('Setup','SaveLocation',FSaveLocation);
LIni.WriteString('Setup','SaveFile',FSaveFile);
LIni.WriteString('Setup','TempFile',FTempFile);
LIni.WriteString('Setup','FileSize',FloatToStr(FFileSize));
finally
LIni.Free;
end;
end;
procedure TWnDownLoadThread.SetHttpProxy;
begin
if not Assigned(FHttp) then Exit;
with FProxy do
if FIsProxyEnabled then
begin
FHttp.Socket.SocksInfo.Version := FSocksVersion;
FHttp.Socket.SocksInfo.Host := FProxyHost;
FHttp.Socket.SocksInfo.Port := FProxyPort;
if FHttp.Socket.SocksInfo.Username <> '' then
FHttp.Socket.SocksInfo.Authentication := saUsernamePassword
else
FHttp.Socket.SocksInfo.Authentication := saNoAuthentication;
FHttp.AuthUsername := FAuthUserName;
FHttp.AuthPassword := FAuthPassword;
FHttp.AuthDomain := FAuthDomain;
FHttp.ProxyHost := FProxyHost;
FHttp.ProxyPort := FProxyPort;
end;
end;
procedure TWnDownLoadThread.SetOnLog(const Value: TDolog);
begin
FOnLog := Value;
end;
procedure TWnDownLoadThread.SetProgress(const Value: TWnDownloadProgress);
begin
FProgress := Value;
end;
procedure TWnDownLoadThread.SetProxy(const Value: PWnProxySetting);
begin
//New(FProxy);
FProxy.FIsProxyEnabled :=Value^.FIsProxyEnabled;
FProxy.FSocksVersion := Value^.FSocksVersion;
FProxy.FProxyHost := Value^.FProxyHost;
FProxy.FProxyPort := Value^.FProxyPort;
FProxy.FAuthUserName := Value^.FAuthUserName;
FProxy.FAuthPassword := Value^.FAuthPassword;
FProxy.FAuthDomain := Value^.FAuthDomain;
FProxy.FProxyHost := Value^.FProxyHost;
FProxy.FProxyPort := Value^.FProxyPort;
end;
procedure TWnDownLoadThread.SetReLoad(const Value: Boolean);
begin
FReLoad := Value;
end;
procedure TWnDownLoadThread.SetSaveLocation(const Value: string);
begin
FSaveLocation := Value;
if FSaveLocation[Length(FSaveLocation)] <> '\' then
FSaveLocation := FSaveLocation +'\';
end;
procedure TWnDownLoadThread.SetTarget(const Value: string);
begin
if Length(Value) = 0 then Exit;
if UpperCase(Copy(Value,1,7)) <> 'HTTP://' then Exit;
FTarget := Value;
end;
end.