-
Привет мастерам!
Нужна сделать прогу для отправки и приёму файлов в FTP сервер. Нужно сделать так чтобы по таймеру обновлял файлы(отправка/приём). Этакое маленькое служба почты. Нашел пример и по примеру сделал процедуру
отправка
procedure FTPUpload();
var IdFTP:TIdFtp;
dn:integer;
F: TSearchRec;
begin
try
IdFTP:=TIdFTP.Create(nil);
if IdFTP.Connected then
begin
IdFTP.Abort;
IdFTP.Quit;
end;
IdFTP.Username := UserName;
IdFTP.Password := UserPass;
IdFTP.Host := FTPIp;
try
IdFTP.Connect;
if IdFTP.Connected then
begin
IdFTP.ChangeDir('/Send');
chdir('D:\Send\');
dn := FindFirst('*.*',faArchive,F);
while dn = 0 do
begin
IdFTP.Put('D:\Send\'+f.name,f.name);
dn := FindNext(F);
end;
IdFTP.Quit;
end;
ShowMessage('Загрузка завершена.');
except
ShowMessage('Ошибка отправки.');
end;
finally
IdFTP.Free;
end;
end;
приём
procedure FTPDownload();
var IdFTP:TIdFtp;
dn:integer;
F: TSearchRec;
begin
try
IdFTP:=TIdFTP.Create(nil);
if IdFTP.Connected then
begin
IdFTP.Abort;
IdFTP.Quit;
end;
IdFTP.Username := UserName;
IdFTP.Password := UserPass;
IdFTP.Host := FTPIp;
try
IdFTP.Connect;
if IdFTP.Connected then
begin
IdFTP.ChangeDir('/Recv');
dn := FindFirst('*.*',faArchive,F);
while dn = 0 do
begin
IdFTP.Get(f.name, 'D:\Recv\'+f.name);
dn := FindNext(F);
end;
IdFTP.Quit;
end;
ShowMessage('Прём файлов завершен.');
except
ShowMessage('Ошибка приёма.');
end;
finally
IdFTP.Free;
end;
end;
Довнлоад каталога не получается по имени файла нормально получается.
И как нужно правильно организовать работу с FTP сервером
-
Либо проблем нет либо они есть и вполне конкретные.
А "не получается" - в программировании нет такого слова)
-
> Xmen (15.11.2011 08:25:00) [0]
Я в растерянности, то получается, то нет
> не получается по имени файла нормально получается.
-
Изменяюсь за то что конкретно не описал задачу и проблему.
У меня получается Upload каталога а Download каталога не работает. Одного файла скачать получился по имени файла а несколько файлов не получился
dn := FindFirst('*.*',faArchive,F);
while dn = 0 do
begin
IdFTP.Get(f.name, 'D:\Recv\'+f.name);
dn := FindNext(F);
end;
не работает. IdFTP.Get('1.doc', 'D:\Recv\1.doc'); работает.
У меня обработка каталога не получился.
И вопрос я ранше не работал с FTP, как работает докачка файла.
-
> Xmen (15.11.2011 10:18:03) [3]
Странно однако, в FindFirst *.*, а в Get f.name
Спрашивается зачем же нужен FindFirst если оно не используется, кроме того
неужели ты думаешь что в папке может быть более одного файла с одинаковым
имением, ты просто оптимист.
Да и справка говорит, что такого прототива вызова нет. Второй параметр
должен быть потоком
-
> Download каталога не работает
FindFirst вообще-то функция для локальной ФС. Какое отношение она к download имеет?
-
То то у меня справка нашла, а надо для Инди, а там такой функции нет
-
> Xmen (15.11.11 10:18) [3]
>
> Изменяюсь за то что конкретно не описал задачу и проблему.
>
> У меня получается Upload каталога а Download каталога не
> работает.
Так как он может работать? Файлы у тебя лежат на сервере, а список ты ищеш локально.
TidFtp.List + F1
-
Вот поэтому и спрашивал
TidFtp.List нашел
и пример автор которого Куликов Алексей после изменения код такой
procedure Download;
var
IdFTP:TIdFtp;
Path: string;
FileList : TStringList;
jj: Integer;
begin
IdFTP:=TIdFTP.Create(nil);
if IdFTP.Connected then
begin
IdFTP.Abort;
IdFTP.Quit;
end;
IdFTP.Username := UserName;
IdFTP.Password := UserPass;
IdFTP.Host := FTPIp;
Path := 'D:\Recv\';
try
IdFTP.Connect();
idFTP.ChangeDir('/Recv');
try
FileList := TStringList.Create;
idFTP.List(FileList,'*.*',False);
for jj := 0 to FileList.Count-1 do
begin
try
idFTP.Get(FileList[jj], Path + FileList[jj], True);
except
on E: Exception do
ShowMessage(Format('Ошибка скачивания',[FileList[jj], E.ClassName, E.Message]));
end;
end;
finally
FreeAndNil(FileList);
end;
IdFTP.Disconnect
except
on E: Exception do
showmessage('Error!'#13#10+E.Message);
end;
И как организовать докачку файла.
-
В протоколе команды rest/reget
В инди смотри сначала resime/restpos
-
IdFTP1.ResumeSupported Это?
-
> Xmen (15.11.2011 14:38:10) [10]
Там в справке все хорошо описано.
-
изменил код на это
idFTP.Get(FileList[jj], Path + FileList[jj], False, True);
Теперь правильно?
-
Вот другая ошибка при Upload е получил такую ошибку. Файл был где то 50 мегабайтов. Загрузил 9 мегабайтов и получил ошибку. Докачка не получился
Socket Error #10054 Connection reset by per
-
Воспользовался примером
Demo Name: FTP Client Demo
Created By: Doychin Bondzhev
On: 27/10/2002
Notes:
FTP Client Demo
и он тоже вернул ошибку
Socket Error #10054 Connection reset by per
Где может быт ошибка, как можно решит проблему?
-
Возьми на вооружение модуль ftpsend из состава Synapse и не мучайся
-
> Xmen (16.11.2011 07:54:14) [14]
Connection reset by peer это не ошибка, а нормальная работа протокола.
-
> Anatoly Podgoretsky © (16.11.11 10:33) [16]
> > Xmen (16.11.2011 07:54:14) [14]Connection reset by peer
> это не ошибка, а нормальная работа протокола.
Это я понял вот как мне сделать так чтобы снова соединяется с сервером.
IdFTP1.Disconnect;
IdFTP1.Socket.Close;
IdFTP1.Connect;
Не получился дала ошибку.
> Сергей М. © (16.11.11 10:10) [15]
> Возьми на вооружение модуль ftpsend из состава Synapse и
> не мучайся
Это отдельная компонента?
И вопрос как правильно организовать работу с FTP сервером. Я так понял что могут быть обрыв связи, докачка файла итд.
Есть ли другой компонент лучший чем Indy, простой в использование а то я по гуглу нетак много нашел. Indy in Depth - не про этот компонент :)
-
> Это отдельная компонента?
Это вообще не "компонента".
В юните ftpsend.pas есть довольно подробные комментарии по использованию класса TFtpSend
-
Indy тоже вполне нормально может работать.
Но у разных фтп-серваков есть свои нюансы. Н-р, кто-то разрешает только пассивный режим и т.п.
-
> Xmen (16.11.11 11:18) [17]
Трудно назвать Инди лучшим.
-
> Indy тоже вполне нормально может работать.
Но не у всех это получается.
-
> Трудно назвать Инди лучшим
"Эт точно" (с) Ф.Сухов
Трижды подумать надо, прежде чем тянуть в проект этого глюкавого монстра ради тривиальной задачи под конкретную платформу
-
> Сергей М. © (16.11.11 11:39) [18]
> > Это отдельная компонента?Это вообще не "компонента".В
> юните ftpsend.pas есть довольно подробные комментарии по
> использованию класса TFtpSend
на этом юните сделал отправку и приём файлов.
procedure TForm1.Button7Click(Sender: TObject);
var dn, i:integer;
F: TSearchRec;
begin
i:=0;
chdir('D:\Send\');
dn := FindFirst('*.*',faArchive,F);
while dn = 0 do
begin
FTPClient.DataStream.LoadFromFile(f.Name);
FTPClient.StoreFile(ExtractFileName(FTPClient.GetCurrentDir+'\Send\'+f.Name),false);
FTPClient.
DeleteFile(f.Name);
Memo1.Lines.Add('Çàãðóæåí ôàéë: '+F.Name+' âðåìÿ çàêà÷êè: '+datetimetostr(NOW));
inc(i);
dn := FindNext(F);
end;
Memo1.Lines.Add('Óñïåøíî çàêà÷àííûõ ôàéëîâ: '+inttostr(i));
refreshDir;
end;
procedure TForm1.Button8Click(Sender: TObject);
var i:integer;
begin
for i := 0 to FTPClient.FtpList.Count-1 do
begin
try
FTPClient.RetrieveFile(FTPClient.GetCurrentDir+'\Recv\'+FTPClient.FtpList[i].FileName,false);
FTPClient.DataStream.SaveToFile('D:\RECV\'+FTPClient.FtpList[i].FileName);
FTPClient.DeleteFile(FTPClient.GetCurrentDir+'\Recv\'+FTPClient.FtpList[i].FileName);
Memo1.Lines.Add('Ñêà÷àí ôàéë: '+FTPClient.FtpList[i].FileName+' âðåìÿ: '+datetimetostr(NOW));
except
on E: Exception do ShowMessage('Îøèáêà ïðè ñêà÷èâàíèè ôàéëà %s'#13#10'class:%s'#13#10'%s'+FTPClient.FtpList[i].FileName);
end;
end;
Memo1.Lines.Add('Óñïåøíî ñêà÷àííûõ ôàéëîâ: '+inttostr(FTPClient.FtpList.Count));
refreshDir;
end;
Теперь нужно организовать процесс процента закачки и скачки через прогрессбар. Как это можно сделать в ftpsend е
-
unit blcksock
..
TBlockSocket
..
{:This event is called by various reasons. It is good for monitoring socket,
create gauges for data transfers, etc.}
property OnStatus: THookSocketStatus read FOnStatus write FOnStatus;
-
> Сергей М. © (18.11.11 15:17) [24]
> unit blcksock..TBlockSocket.. {:This ev
stacktrace: n/a; see opera:config#UserPrefs|Exceptions Have Stacktraceent is called
> by v
stacktrace: n/a; see opera:config#UserPrefs|Exceptions Have Stacktracearious reasons. It is good for monitoring socket,
> create gauges for data transfers, etc.} property OnStatus:
> THookSocketStatus read FOnStatus write FOnStatus;
Спасибо.
как это в коде реализовать?
(уже начинаю тупеть)
-
Вновь вернулся на этот вопрос.
Создал код и оно работает. Но не могу понять вот если соединения разорвался в ФТП отправлен файл но не полностью как там в ФТП узнать что этот файл неполный то есть я должен скопировать эту папку с файлами и не должен скопировать такие файлы.
-
По протоколу разрыв соединения есть признак окончания передачи. Поэтому на FTP серверах рядом с файлом помещают файл с контрольной суммой.
-
> Anatoly Podgoretsky © (13.12.11 15:10) [27]
> По протоколу разрыв соединения есть признак окончания передачи.
> Поэтому на FTP серверах рядом с файлом помещают файл с
> контрольной суммой.
Сейчас проверю
-
Сервер FileZila клиент Total отправил 2 гига файла и отменил копирование. Поискал этот файл с контрольной суммой но не нашел. Где искать надо?
У меня есть клиент на Delphi.
-
Ты его сам должен послать, автоматом это не делается.
-
То есть как?
Путём сравнения файла?
Помогите еще ...
-
> Xmen (13.12.2011 15:40:31) [31]
Очень просто, на сервер отсылаются два файла, а при считывании расчитывается
новая контрольная суммв, если она не совпадает, то ошибка передачи.
-
То есть я сначала пишу контрольную сумму в файл и скопирую файл с текстом контрольной суммой в FTP. Потом идет сравнение файла.
-
> Xmen (13.12.2011 16:14:33) [33]
Нет файлы (оба) тоже надо отправить на сервер
-
> Anatoly Podgoretsky © (13.12.11 16:25) [34]
> > Xmen (13.12.2011 16:14:33) [33]Нет файлы (оба) тоже
> надо отправить на сервер
Да уважаемый гуру я это понял, наверно сначала должен отправит контрольный файл а потом сам файл. Когда копирую с ФТП сначала идет сравнение а потом копирование и удаление контрольного файла или когда закачка на сервер файла закончена то удаляю контрольный файл.
-
> Xmen (13.12.2011 16:44:35) [35]
Конечно первым контрольный файл.
Копирование идет всегда, иначе сравнение не возможно.
На сервере файл не надо удалять.
-
Можете проверит сделал так.
var dn, i, j:integer;
F: TSearchRec;
MyFile:TextFile;
newFile, ftpFileName:string;
ftpFileSize:Integer;
begin
LogFTP;
if FTPStatus=1 then
if ListView3.Items.Count>0 then
begin
i:=0;
ProgressBar2.Max:= ListView3.Items.Count-1;
ProgressBar2.Min := 0;
ProgressBar2.Position := 0;
Memo1.Lines.Add('Открыт соединение с сервером');
dn := FindFirst(path+'Send\*.*',faArchive,F);
while dn = 0 do
begin
ProgressBar1.Position := 0;
TotalBytes :=F.Size;
newFile:=copy(f.Name,1,Length(f.Name)-4)+'.crc';
AssignFile(MyFile,path+'Send\'+newFile);
try
Rewrite(MyFile);
Write(MyFile,TotalBytes);
finally
CloseFile(MyFile);
FTPClient.DataStream.LoadFromFile(path+'Send\'+newFile);
FTPClient.StoreFile(ExtractFileName(FTPClient.GetCurrentDir+'Send/'+NewFile), false);
end;
FTPClient.DSock.OnStatus := SockPutCallBack;
FTPClient.DataStream.LoadFromFile(path+'Send\'+f.Name);
Memo1.Lines.Add('Отправка файла: ' + f.Name+' Размер: ' + IntToStr(TotalBytes));
if FTPClient.StoreFile(ExtractFileName(FTPClient.GetCurrentDir+'Send/'+f.Name), false) = true then
begin
FTPClient.List(FTPClient.GetCurrentDir+'/Send/',false);
for j := 0 to FTPClient.FtpList.Count-1 do
begin
ftpFileName:= FTPClient.FtpList[j].FileName ;
ftpFileSize:= FTPClient.FileSize(FTPClient.GetCurrentDir+'Send/'+FTPClient.FtpList[j].FileName);;
if (ftpFileName=f.Name) and (TotalBytes = ftpFileSize) then
begin
Memo1.Lines.Add('Загружен файл: '+F.Name+' время закачки: '+datetimetostr(NOW));
inc(i);
DeleteFile(path+'Send\'+f.Name);
DeleteFile(path+'Send\'+NewFile);
Break;
end;
end;
ProgressBar1.Position := 0;
Update;
end
else Memo1.lines.add('Ошибка отправки');
ProgressBar2.Position := ProgressBar2.Position + 1;
dn := FindNext(F);
end;
Memo1.Lines.Add('Успешно закачанных файлов: '+inttostr(i));
Memo1.Lines.Add('Соединение закрыто');
ProgressBar2.Position :=0;
end;
LogoutFTP;
end;
Это для отправки в сервер.
-
> Xmen (15.12.2011 11:35:37) [37]
> ftpFileSize:=
> FTPClient.FileSize(FTPClient.GetCurrentDir+'Send/'+FTPClient.FtpList[j].FileName);;//если
> в сервер закачан файл и его размер подходит то ..
Это не гарантирует целостности файла
-
а как нужно тогда правильно сделать
-
> Xmen (15.12.2011 13:24:39) [39]
Как сказано, создавать файл с контрольной суммой, Свму сумму можно в
название включить. В качестве КС лучше использовать хеш 64, будет более
стандартно
-
function GetCheckSum(FileName: string): DWORD;
var
F: file of DWORD;
P: Pointer;
Fsize: DWORD;
Buffer: array[0..500] of DWORD;
begin
FileMode := 0;
AssignFile(F, FileName);
Reset(F);
Seek(F, FileSize(F) div 2);
Fsize := FileSize(F) - 1 - FilePos(F);
if Fsize > 500 then
Fsize := 500;
BlockRead(F, Buffer, Fsize);
Close(F);
P := @Buffer;
asm
xor eax, eax
xor ecx, ecx
mov edi , p
@again:
add eax, [edi + 4*ecx]
inc ecx
cmp ecx, fsize
jl @again
mov @result, eax
end;
end;
Использовал так:
ShowMessage(IntToStr(GetCheckSum(path+'Send\'+f.Name)));
а как его в название включит ?
у меня все файлы в формате 8.3.
про хеш 64 инфы не нашел
-
почитал.
http://www.delphimaster.net/view/15-1195018398/all>>Свму сумму можно в название включить.
в название не могу написать потому что у меня название файла это шаблон
например (ФФФФрнф.ффф
ФФФФ - филиал получатель
ф.ффф - филиал отправитель
р - номер рейса (номер отправленного файла 0-9 a-z)
н - номер дня (0-9 a-r)
-
> Xmen (16.12.2011 10:03:42) [42]
Не можешь, ни и не надо, придется считывать файлик.
В FTP используется включения суммы в название, и ХЕШ в 64 байта, но это не
важно, что бы с стандаром совпадало, главное, что бы свою роль выполняло и
обнаруживало более одной ошибки передачи..
-
и забыл сказать у меня все файлы для отправки и приёма архивируется с помощью arj. Где то читал что есть у него свойство по работе с CRC. Можно как нибуд это использовать это в проге?