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 , 即一次只准一个线程去调用,以避免形成冲突。