idftp 上傳數據庫
多個文件同時上傳,支持斷點續傳,多進度條。服務器
起初用API作,發現對API瞭解太少,便改用線程類來處理,代碼以下ide
TThread1 = class(TThread)
private
fCount, tstart, tlast: integer;
tURL, tFile, temFileName,temLocalFile: string;
tResume: Boolean;
tStream: TFileStream;
temFtp: TIdFTP;
sFileName: string;
pb: TProgressBar;
bstate:Integer; //1,表示準備上傳,2表示正在上傳,3表示上傳完成,4表示上傳失敗函數
protected
procedure Execute; override;
public
constructor create1(aURL, aFile, fileName,localfile: string; bResume: Boolean; Count,
start, last: integer);
procedure DownLodeFile(); //上傳文件
// function SetProgressInListView(lvw: TListView): Boolean; //在listview中動態建立進度條
procedure StateChange; //上傳狀態改變
procedure FtpUp;
end;線程
建立線程以前把進度條動態建立好,給進度條的Tag屬性賦個惟一值,orm
for i:=0 to iCount-1 do
begin
SetProgressInListView(ListView1,i,1,10,3); // 建立進度條
localfile:=ListView1.Items.Item[i].Caption;
MyThread[i+1] := TThread1.create1('', '', '',localfile, false,i,2,1);
end;同步
constructor TThread1.create1(aURL, aFile, fileName,localfile: string; bResume: Boolean;
Count, start, last: integer);
var
i:Integer;
begin
inherited create(true); //設置爲true 主要是爲了調用resume 即建立線程時先不執行,調用thread1.resume執行線程。
freeonterminate:=true;
tURL := aURL;
tFile := aFile;
fCount := Count;
tResume := bResume;
tstart := start;
tlast := last;
temFileName := fileName;
temLocalFile:=localfile;
for i:=0 to Form1.ComponentCount-1 do
begin //將建好的進度條與線程先對應
if Form1.Components[i] is TProgressBar then
if Form1.Components[i].Tag=fcount then
begin
pb:=TProgressBar(Form1.Components[i]);
end;
end;
end;string
將線程與進度條相對應,線程中的變量最好在線程類中定義,每一個線程都有一塊空間存儲變量的值。上代碼中it
inherited create(true); 設爲true ,因此須要調用TThread.resume來啓動線程io
while j <= iCount do
begin
MyThread[j].Resume; //喚醒線程
j := j + 1;
end;
線程執行函數: 執行一次線程,動態建立一個IDFTP控件,將本地文件存成一個流,若是大於1M,則分段截取傳送。
procedure TThread1.DownLodeFile();
const
SEND_BUFFER=1048576;// 一次提交1M的東西
var
AFileStream: TFileStream;
AsFileStream: TMemoryStream;
begin
bstate:=1;
Synchronize(StateChange);
try
temFtp := TIdFTP.Create(nil);
temFtp.Host:=Form1.IPEdit.Text;
temFtp.Username:=Form1.NameEdit.Text;
temFtp.Password:=Form1.PwdEdit.Text;
temFtp.Port:=StrToInt(Form1.PortEdit.Text);
temFtp.Connect;
temFtp.onWorkBegin := Form1.IdFTP1WorkBegin;
temFtp.onwork := Form1.IdFTP1work;
sFileName := ExtractFileName(temLocalFile);
AFileStream := TFileStream.Create(temLocalFile, fmOpenRead);
// temFtp.ChangeDir('LoacalUser'); //改變服務器端目錄
try
// 獲取斷點
AFileStream.Seek(temFtp.Size(sFileName), soFromBeginning);
// 開始斷點續傳
AsFileStream:= TMemoryStream.Create;
pb.Max:=AFileStream.Size; //進度條賦值
pb.min:=0;
bstate:=2;
Synchronize(StateChange);
try
while (AFileStream.Position < AFileStream.Size) do
begin
sleep(300); //等待時間太長
AsFileStream.Clear;
AsFileStream.CopyFrom(AFileStream, Min(SEND_BUFFER, AFileStream.Size - AFileStream.Position));
// AsFileStream.CopyFrom(AFileStream,AFileStream.Size - AFileStream.Position);
AsFileStream.Position:=0;
temFtp.Put(AsFileStream, sFileName, true);
pb.Position:=AFileStream.Position;
end;
pb.Position:=AFileStream.Size;
bstate:=3;
Synchronize(StateChange);
AsFileStream.Free;
AFileStream.free;
except
bstate:=4;
Synchronize(StateChange);
AsFileStream.Free;
AFileStream.free;
raise;
end;
// 判斷是否上傳完畢
{ if AFileStream.Position = AFileStream.Size then
ShowMessage('上傳完畢!')
else
ShowMessage('下次記得繼續續傳~');
synchronize(StateChange(true));
AFileStream.Free;
}
except
bstate:=4;
Synchronize(StateChange);
AFileStream.Free;
// ShowMessage('出錯... - -');
end;
finally
Synchronize(FtpUp); //添加到數據庫
temFtp.free;
end;
end;
當線程須要調用窗口的控件時,最好同步Synchronize , 即一次只准一個線程去調用,以避免形成衝突。