问题是这样的:
有一个远程的URL下载地址列表,如:
http://www.xxx.com/a.rar
http://www.xxx.com/b.rar
http://www.xxx.com/c.rar
http://www.xxx.com/d.rar
......
保存在一个Tstringlist中的.
我要把远程的这些文件下载下来,保存到C盘下面的doc目录中(c:\doc)
目前,远程下载函数已经写好了。我采用多线程下载。
但前提是,当第一个线程下载完后才执行第二个线程。一直到最后一个线程结束。
在写个TThread的时候我遇到了问题。
就是线程不能同步,线程是一起在执行,影响了界面上的进度显示。
(界面上有两个控件,一个进度条用来显示当前下载文件的进度,一个lable用来显示当前下载文件的字节/当前文件总字节)
我把我的代码发出来。注意高手能帮我找出问题出在哪里。
小弟出了送分外,就只有由心的感谢了。
线程单元:
///////////////////////////////////////////////////////unit DownThreadUnit;
interfaceuses
Windows, Messages, SysUtils, Classes, WinInet,extctrls,ComCtrls,Dialogs,
StdCtrls,Gauges;Type
DownThread = class(TThread)
private
FTAcceptTypes,
FTAgent,
FTURL,
FTFileName,
FTStringResult,
FTUserName,
FTPassword,
FTPostQuery,
FTReferer: String;
FTBinaryData,
FTUseCache: Boolean;
FTResult: Boolean; FTFileSize,
FTPort : Integer;
FTToFile: Boolean;
BytesToRead,
BytesReaded: DWord;
ProBar : TGauge;
pLabel : TLabel; protected
procedure InitProBar;
procedure ShowProBar;
procedure DownFiles;
procedure Execute; override;
public
constructor Create(aProBar : TGauge;aLabel : TLabel;RemoteUrl,aSaveFileName:String);
end;implementationConstructor DownThread.Create(aProBar : TGauge;aLabel : TLabel;RemoteUrl,aSaveFileName:string);
// aProBar 进度条.aLabel 下载字节显示. RemoteUrl 下载地址 . aSaveFileName 保存的文件名
begin inherited Create(False);
FTAcceptTypes := '*/*';
FTAgent := 'Blue Steel Update/1.1'; FTURL := RemoteUrl; //下载的URL地址.
FTUserName := ''; //用户名.
FTPassword := ''; //密码.
FTPort := 80; //端口.
ProBar := aProBar;
pLabel := aLabel;
FTFileName := aSaveFileName; //保存的文件名.
FTPostQuery := 'GET';
FTReferer := '';
FTBinaryData := False;
FTUseCache := False;
FTToFile := True; //下载文件.
FreeOnTerminate := True;
end;procedure DownThread.InitProBar;
Begin
ProBar.Progress := 0;
ProBar.MinValue := 0;
ProBar.MaxValue := 100; {文件总大小}
pLabel.Caption := '0/'+IntTostr(FTFileSize);
End;Procedure DownThread.ShowProBar;
Begin
ProBar.Progress := Trunc((BytesToRead / FTFileSize)*100);
ProBar.Update;
pLabel.Caption := IntTostr(BytesReaded)+'/'+IntTostr(FTFileSize);
{更新下载显示.}
End;procedure DownThread.DownFiles; //下载函数.
Var
hSession, hConnect, hRequest: hInternet;
HostName, FileName: String;
f: File;
Buf: Pointer;
dwBufLen, dwIndex: DWord;
Data: Array[0..$400] of Char;
TempStr: String;
RequestMethod: PChar;
InternetFlag: DWord;
TimeOut : Cardinal;
AcceptType: LPStr;
Procedure ParseURL(URL: String; var HostName, FileName: String);
Var
i: Integer;
Begin
if Pos('http://', LowerCase(URL)) <> 0 then
System.Delete(URL, 1, 7); i := Pos('/', URL);
HostName := Copy(URL, 1, i);
FileName := Copy(URL, i, Length(URL) - i + 1);
if (Length(HostName) > 0) and (HostName[Length(HostName)] = '/') then
SetLength(HostName, Length(HostName) - 1);
End; Procedure CloseHandles;
begin
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
end;
begin
try
TimeOut := 6000000;
ParseURL(FTURL, HostName, FileName); if Terminated then
begin
FTResult := False;
Exit;
end; if FTAgent <> '' then
hSession := InternetOpen(PChar(FTAgent),
INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0)
else
hSession := InternetOpen(nil,
INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); hConnect := InternetConnect(hSession, PChar(HostName),
FTPort, PChar(FTUserName), PChar(FTPassword),
INTERNET_SERVICE_HTTP, 0, 0); RequestMethod := PChar(FTPostQuery); // 'GET' If FTUseCache Then InternetFlag := 0
Else InternetFlag := INTERNET_FLAG_RELOAD; AcceptType := PChar('Accept: ' + FTAcceptTypes);
hRequest := HttpOpenRequest(hConnect, RequestMethod, PChar(FileName), 'HTTP/1.1',
PChar(FTReferer), @AcceptType, InternetFlag, 0); InternetSetOption(hRequest, INTERNET_OPTION_CONNECT_TIMEOUT,
@TimeOut, SizeOf(TimeOut));
InternetSetOption(hRequest, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT,
@TimeOut, SizeOf(TimeOut));
if FTPostQuery = '' then
HttpSendRequest(hRequest, nil, 0, nil, 0)
else
HttpSendRequest(hRequest, 'Content-Type: application/x-www-form-urlencoded', 47,
PChar(FTPostQuery), Length(FTPostQuery)); if Terminated then
begin
CloseHandles;
FTResult := False;
Exit;
end; dwIndex := 0;
dwBufLen := 1024;
GetMem(Buf, dwBufLen); FTResult := HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH,
Buf, dwBufLen, dwIndex); if Terminated then
begin
FreeMem(Buf);
CloseHandles;
FTResult := False;
Exit;
end; if FTResult or (not FTBinaryData) then
begin IF FTResult then begin
FTFileSize := StrToInt(StrPas(Buf));
synchronize(InitProBar); // 初始化进度条.
End; BytesReaded := 0; If FTToFile then
Begin
AssignFile(f, FTFileName);
Rewrite(f, 1);
End
else FTStringResult := ''; while True do
begin
IF not InternetReadFile(hRequest, @Data, SizeOf(Data), BytesToRead) then
break
Else
IF BytesToRead = 0 then Break
Else begin
if FTToFile then begin
if Not FTResult then exit;
BlockWrite(f, Data, BytesToRead);
End
else begin
TempStr := Data;
SetLength(TempStr, BytesToRead);
FTStringResult := FTStringResult + Data;
end;
BytesReaded := BytesReaded + BytesToRead;
synchronize(ShowProBar); //显示进度条.
end;
End; if FTToFile then
FTResult := FTFileSize = Integer(BytesReaded)
else begin
SetLength(FTStringResult, BytesReaded);
FTResult := BytesReaded <> 0;
end; if FTToFile then CloseFile(f); End;
FreeMem(Buf);
CloseHandles;
Except
CloseHandles;
End;
inherited Destroy;end;procedure DownThread.Execute;
Begin
DownFiles;
End;end./////////////////////////////////////////////
线程单元结束
线程在主表单中的调用过程
....
var
i : integer;
Flist : TStringList;
begin FList := TStringList.Create;
Flist.add('http://www.xxx.com/a.rar');
Flist.add('http://www.xxx.com/b.rar');
...... For i:=0 to FList.Count-1 do Begin
DownThread.Create(Gauge,Lprogress,FList.String[i],'C:\doc'+DateTimeToStr(Now())+'.rar' );
// Gauge 是进度条.
// Lprogress 是一个label.
End; Flist.Free;
end;
..... 程式编译完全没有问题。只是在运行的时候线程,不能同步(找了些资料修改了代码也不行.我笨.)
希望大哥们,能帮我看看! 顶的朋友有分,大家一起学习! :)
有一个远程的URL下载地址列表,如:
http://www.xxx.com/a.rar
http://www.xxx.com/b.rar
http://www.xxx.com/c.rar
http://www.xxx.com/d.rar
......
保存在一个Tstringlist中的.
我要把远程的这些文件下载下来,保存到C盘下面的doc目录中(c:\doc)
目前,远程下载函数已经写好了。我采用多线程下载。
但前提是,当第一个线程下载完后才执行第二个线程。一直到最后一个线程结束。
在写个TThread的时候我遇到了问题。
就是线程不能同步,线程是一起在执行,影响了界面上的进度显示。
(界面上有两个控件,一个进度条用来显示当前下载文件的进度,一个lable用来显示当前下载文件的字节/当前文件总字节)
我把我的代码发出来。注意高手能帮我找出问题出在哪里。
小弟出了送分外,就只有由心的感谢了。
线程单元:
///////////////////////////////////////////////////////unit DownThreadUnit;
interfaceuses
Windows, Messages, SysUtils, Classes, WinInet,extctrls,ComCtrls,Dialogs,
StdCtrls,Gauges;Type
DownThread = class(TThread)
private
FTAcceptTypes,
FTAgent,
FTURL,
FTFileName,
FTStringResult,
FTUserName,
FTPassword,
FTPostQuery,
FTReferer: String;
FTBinaryData,
FTUseCache: Boolean;
FTResult: Boolean; FTFileSize,
FTPort : Integer;
FTToFile: Boolean;
BytesToRead,
BytesReaded: DWord;
ProBar : TGauge;
pLabel : TLabel; protected
procedure InitProBar;
procedure ShowProBar;
procedure DownFiles;
procedure Execute; override;
public
constructor Create(aProBar : TGauge;aLabel : TLabel;RemoteUrl,aSaveFileName:String);
end;implementationConstructor DownThread.Create(aProBar : TGauge;aLabel : TLabel;RemoteUrl,aSaveFileName:string);
// aProBar 进度条.aLabel 下载字节显示. RemoteUrl 下载地址 . aSaveFileName 保存的文件名
begin inherited Create(False);
FTAcceptTypes := '*/*';
FTAgent := 'Blue Steel Update/1.1'; FTURL := RemoteUrl; //下载的URL地址.
FTUserName := ''; //用户名.
FTPassword := ''; //密码.
FTPort := 80; //端口.
ProBar := aProBar;
pLabel := aLabel;
FTFileName := aSaveFileName; //保存的文件名.
FTPostQuery := 'GET';
FTReferer := '';
FTBinaryData := False;
FTUseCache := False;
FTToFile := True; //下载文件.
FreeOnTerminate := True;
end;procedure DownThread.InitProBar;
Begin
ProBar.Progress := 0;
ProBar.MinValue := 0;
ProBar.MaxValue := 100; {文件总大小}
pLabel.Caption := '0/'+IntTostr(FTFileSize);
End;Procedure DownThread.ShowProBar;
Begin
ProBar.Progress := Trunc((BytesToRead / FTFileSize)*100);
ProBar.Update;
pLabel.Caption := IntTostr(BytesReaded)+'/'+IntTostr(FTFileSize);
{更新下载显示.}
End;procedure DownThread.DownFiles; //下载函数.
Var
hSession, hConnect, hRequest: hInternet;
HostName, FileName: String;
f: File;
Buf: Pointer;
dwBufLen, dwIndex: DWord;
Data: Array[0..$400] of Char;
TempStr: String;
RequestMethod: PChar;
InternetFlag: DWord;
TimeOut : Cardinal;
AcceptType: LPStr;
Procedure ParseURL(URL: String; var HostName, FileName: String);
Var
i: Integer;
Begin
if Pos('http://', LowerCase(URL)) <> 0 then
System.Delete(URL, 1, 7); i := Pos('/', URL);
HostName := Copy(URL, 1, i);
FileName := Copy(URL, i, Length(URL) - i + 1);
if (Length(HostName) > 0) and (HostName[Length(HostName)] = '/') then
SetLength(HostName, Length(HostName) - 1);
End; Procedure CloseHandles;
begin
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
end;
begin
try
TimeOut := 6000000;
ParseURL(FTURL, HostName, FileName); if Terminated then
begin
FTResult := False;
Exit;
end; if FTAgent <> '' then
hSession := InternetOpen(PChar(FTAgent),
INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0)
else
hSession := InternetOpen(nil,
INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); hConnect := InternetConnect(hSession, PChar(HostName),
FTPort, PChar(FTUserName), PChar(FTPassword),
INTERNET_SERVICE_HTTP, 0, 0); RequestMethod := PChar(FTPostQuery); // 'GET' If FTUseCache Then InternetFlag := 0
Else InternetFlag := INTERNET_FLAG_RELOAD; AcceptType := PChar('Accept: ' + FTAcceptTypes);
hRequest := HttpOpenRequest(hConnect, RequestMethod, PChar(FileName), 'HTTP/1.1',
PChar(FTReferer), @AcceptType, InternetFlag, 0); InternetSetOption(hRequest, INTERNET_OPTION_CONNECT_TIMEOUT,
@TimeOut, SizeOf(TimeOut));
InternetSetOption(hRequest, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT,
@TimeOut, SizeOf(TimeOut));
if FTPostQuery = '' then
HttpSendRequest(hRequest, nil, 0, nil, 0)
else
HttpSendRequest(hRequest, 'Content-Type: application/x-www-form-urlencoded', 47,
PChar(FTPostQuery), Length(FTPostQuery)); if Terminated then
begin
CloseHandles;
FTResult := False;
Exit;
end; dwIndex := 0;
dwBufLen := 1024;
GetMem(Buf, dwBufLen); FTResult := HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH,
Buf, dwBufLen, dwIndex); if Terminated then
begin
FreeMem(Buf);
CloseHandles;
FTResult := False;
Exit;
end; if FTResult or (not FTBinaryData) then
begin IF FTResult then begin
FTFileSize := StrToInt(StrPas(Buf));
synchronize(InitProBar); // 初始化进度条.
End; BytesReaded := 0; If FTToFile then
Begin
AssignFile(f, FTFileName);
Rewrite(f, 1);
End
else FTStringResult := ''; while True do
begin
IF not InternetReadFile(hRequest, @Data, SizeOf(Data), BytesToRead) then
break
Else
IF BytesToRead = 0 then Break
Else begin
if FTToFile then begin
if Not FTResult then exit;
BlockWrite(f, Data, BytesToRead);
End
else begin
TempStr := Data;
SetLength(TempStr, BytesToRead);
FTStringResult := FTStringResult + Data;
end;
BytesReaded := BytesReaded + BytesToRead;
synchronize(ShowProBar); //显示进度条.
end;
End; if FTToFile then
FTResult := FTFileSize = Integer(BytesReaded)
else begin
SetLength(FTStringResult, BytesReaded);
FTResult := BytesReaded <> 0;
end; if FTToFile then CloseFile(f); End;
FreeMem(Buf);
CloseHandles;
Except
CloseHandles;
End;
inherited Destroy;end;procedure DownThread.Execute;
Begin
DownFiles;
End;end./////////////////////////////////////////////
线程单元结束
线程在主表单中的调用过程
....
var
i : integer;
Flist : TStringList;
begin FList := TStringList.Create;
Flist.add('http://www.xxx.com/a.rar');
Flist.add('http://www.xxx.com/b.rar');
...... For i:=0 to FList.Count-1 do Begin
DownThread.Create(Gauge,Lprogress,FList.String[i],'C:\doc'+DateTimeToStr(Now())+'.rar' );
// Gauge 是进度条.
// Lprogress 是一个label.
End; Flist.Free;
end;
..... 程式编译完全没有问题。只是在运行的时候线程,不能同步(找了些资料修改了代码也不行.我笨.)
希望大哥们,能帮我看看! 顶的朋友有分,大家一起学习! :)
>> 但前提是,当第一个线程下载完后才执行第二个线程。一直到最后一个线程结束。這樣的多線程??有意義嗎??
DownThread := TDownThread.Create(Gauge,Lprogress,FList.String[i],'C:\doc'+DateTimeToStr(Now())+'.rar' );
DownThread.resume;
DownThread.waitfor;
// Gauge 是进度条.
// Lprogress 是一个label.
End;
DownThread = class(TThread)
谢谢你的回复,因为在单线程中,下载的时候窗口被锁定了。
不能移动窗口,不好意思我比较菜!
谢谢加入这两句后。
程序正常了很感谢你。DownThread.resume;
DownThread.waitfor;
:)
接分了。
一般, 如你這種情況, 應該在主線和處理進度條之類的更新
或單獨用個線程來處理 UI ,
其它後台線程, 只是postMessage一個消息給處理界面的線程而已
一般, 如你這種情況, 應該在主線和處理進度條之類的更新
或單獨用個線程來處理 UI ,
其它後台線程, 只是postMessage一個消息給處理界面的線程而已