уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Сегодня рассмотрим работу с ещё одним сетевым протоколом с использованием библиотеки SynapseFile Transfer Protocol (FTP).

Давно уже собирался написать про него, но всё как-то было лень :) Сегодня решил всё-таки выкроить немного времени и разобраться с работой с FTP-протоколом в Synapse. Для начала я решил немного поиздеваться над FTP-шником своего блога и написать небольшую программку, реализующую основные операции: логин, чтение списка каталогов, загрузка на сервер, скачивание с сервера и т.д. Поэтому сегодня рассмотрим рабочий пример, а в конце поста я дам ссылку на страничку описания класса TFTPSend.

Как Вы уже поняли из введения к посту, работа с FTP в Synapse организуется через использование экземпляров класса TFTPSend, который находится в модуле ftpsend.pas. Поэтому можете запускать Delphi и смело подключать этот модуль в uses.

Вначале накидаем компоненты на форму. Я решил сделать главную форму приложения такой:

ftpsend1

На форме расположены:

  1. 4 Edit’а – для определения параметров подключения;
  2. 2 кнопки TButton – для коннекта и дисконнекта (хотите – сделайте одну для обеих операций – это не суть)
  3. 1 ListView для вывода содержимого текущей директории
  4. 1 Memo для ведения лога работы – сюда будем записывать некоторые сообщения от сервера, чисто для наглядности и не более.

1. Коннектимся к серверу

Первое, что нам необходимо – это авторизоваться на сервере. Для этого определим переменную:

FTPClient: TFTPSend;

 

и в обработчике OnClick кнопки «Login» напишем следующий код:

  FTPClient:=TFTPSend.Create;
  FTPClient.TargetHost:=Edit1.Text;
  FTPClient.TargetPort:=Edit2.Text;
  FTPClient.UserName:=Edit3.Text;
  FTPClient.Password:=Edit4.Text;
  FTPClient.PassiveMode:=CheckBox1.Checked;
  if FTPClient.Login then
   begin
     Memo1.Lines.Add('Логин прошел успешно');
   end;

 

Здесь следует обратить внимание на то, что при определении параметров одключения использовались свойства родителя для TFTPSend, т.е. класса TSynaClient. Сам же TFTPSend содержит аналогичные свойства с префиксом «FW» — эти свойства определяются для работы с брендмауэром. Итак мы определили:

  • TargetHost — хост FTP
  • TargetPort — порт (по умолчанию — 21)
  • UserName — имя пользователя
  • Password — пароль доступа

и затем воспользовались методом Login для доступа к серверу. Если Login вернул True — значит коннект прошел успешно и можно продолжать работу (получать список каталогов, качать файлы и т.д.) Движемся далее.

Как узнать текущую директорию в которой мы находимся и перемещаться по директориям?

Для этого у TFTPSend имеется несколько методов:

GetCurrentDir – возвращает имя директории в которой мы находимся на данный момент.

function ChangeWorkingDir(const Directory: string): Boolean; virtual;

Меняет текущую директорию на директорию Directory и, в случае успеха, возвращает True.

function ChangeToParentDir: Boolean; virtual;

Изменяет текущу директория на деректорию, лежащую на один уровень вверх от текущей и, в случае успеха, возвращает True.

function ChangeToRootDir: Boolean; virtual;

Переходит в корневую директорию на сервере. Функция может не сработать (вернуть False), например, в случае, когда используется FTP на бесплатном хостинге — там доступ дается обычно не на корень а на отдельную директорию лежащую на хз каком уровне от Root’а.

Теперь можете дописать обработчик, например так, чтобы в лог выписывалась текущая директория на сервере.

Предположим, что коннект состоялся, мы знаем где находимся на сервере.

Как нам теперь получить список всех директорий и файлов в текущей нашей директории?

Для этого нам потребуется метод:

function List(Directory: string; NameList: Boolean): Boolean; virtual;

 

Загружает список всех директорий и файлов, находящихся в директории Directory. Если свойство Directory имеет нулевое значение (пустая строка), то загружается список из текущей директории. Параметр NameList указывает на то, что загружаться должны только названия директорий и файлов.

Все загруженные данные сохраняются в списке:

property FtpList: TFTPList read FFtpList;

 

Остается совершеннейшая малость – дописать обработчик с целью получения списка всех директорий и файлов, находящихся в текущей директории. Путь он (обработчик) будет у нас теперь таким:

procedure TForm2.Button1Click(Sender: TObject);
var i:integer;
begin
  FTPClient:=TFTPSend.Create;
  FTPClient.TargetHost:=Edit1.Text;
  FTPClient.TargetPort:=Edit2.Text;
  FTPClient.UserName:=Edit3.Text;
  FTPClient.Password:=Edit4.Text;
  FTPClient.PassiveMode:=CheckBox1.Checked;
  if FTPClient.Login then
   begin
     Memo1.Lines.Add('Логин прошел успешно');
     Memo1.Lines.Add('Текущая директория '+FTPClient.GetCurrentDir);
     ListView1.Clear;
     FTPClient.List(FTPClient.GetCurrentDir,false);
     for i := 0 to FTPClient.FtpList.Count-1 do
       begin
         with ListView1.Items.Add do
           begin
             Caption:=FTPClient.FtpList[i].FileName;
             if FTPClient.FtpList[i].Directory then
                SubItems.Add('директория')
             else
               SubItems.Add('файл');
             SubItems.Add(DateToStr(FTPClient.FtpList[i].FileTime))
 
           end;
       end;
   end;
   Memo1.Lines.Add(FTPClient.FullResult.Text);
end;

 

Запустим программу и проверим работу:

ftpsend2

Остается только определиться как скачивать/закачивать файлы.

Для примера, предлагаю бросить на форму TOpenDialog, создать простой txt-файлик и покидать его туда-обратно.

Вначале сделаем загрузку файла НА сервер. В общем случае процедура загрузки файла на сервер может выглядеть следующим образом:

  if OpenDialog1.Execute then
    begin
      FTPClient.DataStream.LoadFromFile(OpenDialog1.FileName);//записали содержимое файла в поток
      FTPClient.StoreFile(ExtractFileName(OpenDialog1.FileName),false);//сохранили на сервер
      FTPClient.List(FTPClient.GetCurrentDir,false);//прочитали новое содержимое директории
      {перечисляем имена директорий и файлов}
    end;

Вначале, записываем всё содержимое файла в поток DataStream. Затем сохраняем содержимое потока на сервере, задав имя файла. После загрузки вновь получаем список файлов и диреторий на сервере и выводим их в ListBox. Остается только отметить, что в функции StoreFile второй параметр указывает — будет ли файл сразу же загружен на сервер или его загрузка будет отложена (при условии, что сервер поддерживает отложенные загрузки). Таким образом Вы можете практически без проблем организовывать в своих программах очереди згрузок. Ну и, наконец, обратная операция — получение файла с сервера. Вид процедуры может быть таким:

 

 FTPClient.RetrieveFile('Имя_файла_на_сервере',false);//прочитали файл в поток
 FTPClient.DataStream.SaveToFile('Имя_файла_на_диске');//сохранили из потока на диск

 

Вот пожалуй и основные навык работы с FTP в Synapse. Думаю, что смысл понятен, а остальное будем разбирать по ходу дела :) Пока можете почитать дополнительно: Что представляет из себя FTP

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
5 2 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
25 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Юрий
Юрий
25/03/2011 01:39

Есть ли докачка в этом компоненте? Как её реализовать?

Макс
Макс
30/04/2011 02:27

Отличная статья, побольше таких надо! Супер полезно и доступно!

Михаил
Михаил
04/07/2012 16:47

вопрос, если работаешь через прокси.
Есть возможность использовать данный модуль? Чтобы писать что-то вроде:
FTPClient.Proxy:=’10.32…’

alex
alex
07/07/2012 12:34

Спасибо за интересный и полезный блог.
Подскажи пожалуйста, как с Tftpsend работать через socks5.

sergey
sergey
22/09/2012 08:49

а можно ли как нибудь в процессе загрузки файла узнавать текущий объем закачанных данных (ну процент загрузки файла)

vvkhr
vvkhr
23/05/2013 14:30

Пришлось по работе бросать файлы на ФТП сервер с SSL. Вроде удалось решить проблему благодаря вашему примеру, но с некоторыми модификациями. В раздел USES добавил плагин ssl_openssl и в свойствах создаваемого клиента FTPClient.FullSSL := True; Но это потребовало тащить с приложением еще две DLL от OpenSSL Прочитал в Синапсе, что можно использовать плагин ssl_streamsec с библиотекой OpenStrSecII. В этом случае можно избавится от ДЛЛ Нашел такую библиотеку, но все мои потуги не дали результатов. Я использую древнюю Дельфи5. Не компилируется ssl_streamsec. Не знает функции Sleep. Для компиляции добавил в USES модуль Windows. Но попытка логина к ФТП серверу стабильно выдает… Подробнее »

vorvv
vorvv
29/07/2013 04:17

if OpenDialog1.Execute then
begin
FTPClient.DataStream.LoadFromFile(OpenDialog1.FileName);//записали содержимое файла в поток
FTPClient.StoreFile(ExtractFileName(OpenDialog1.FileName),false);//сохранили на сервер
FTPClient.List(FTPClient.GetCurrentDir,false);//прочитали новое содержимое директории
{перечисляем имена директорий и файлов}
end;

Как показать в прогресс баре???

rokstuk
rokstuk
07/08/2013 17:38

Не понимаю, передаю таким образом (как описано в материале выше) текстовый файл на фтп, он там успешно появляется..но, почему то пустой( как справиться с проблемой?

rokstuk
rokstuk
07/08/2013 18:04
Ответить на  rokstuk

собственно, сам код:

procedure move_ftp();
begin
FTPClient:=TFTPSend.Create;
FTPClient.TargetHost:=form1.srv_name.Text;
FTPClient.TargetPort:=form1.ftp_prt.Text;
FTPClient.UserName:=form1.usr_name.Text;
FTPClient.Password:=form1.pass.Text;
FTPClient.PassiveMode:=form1.pass_mode.Checked;
if FTPClient.Login then
begin
form1.ftp_info.caption:='Логин прошел успешно';
end else begin
form1.ftp_info.caption:='Неудача';
end;
FTPClient.ChangeToRootDir;
FTPClient.DataStream.LoadFromFile(abs_name);//записали содержимое файла в поток
FTPClient.StoreFile(output_file, false);//сохранили на сервер
end;

vorvv
vorvv
31/08/2013 23:02

Никто так и не знает как делать докачку файла
при закачке/скачке?

vorvv
vorvv
05/09/2013 23:24

Вроде бы раскопал FTPClient.CanResume отвечает как бы поддерживает ли сервер докачку — соотвественно результат True False FTPClient.DataStream.LoadFromFile(OpenDialog1.FileName);//записали содержимое файла в поток FTPClient.StoreFile(ExtractFileName(OpenDialog1.FileName),false);//сохранили на сервер и сдесь во втором параметре «,false);//сохранили на сервер» ставим результат FTPClient.CanResume У меня сработало для загрузки на ftp — тестил на depositfiles.com И еще соотвественно для прогресбара procedure FTPStatus(Sender: TObject; Response: Boolean; const Value: string); begin Memo1.Lines.Add(BoolToStr(Response,true)+’ Значение ‘+Value) if bfCanResumeFtp=True then begin if Pos(‘REST’,Value)>0 then begin if strtoint(copy(value,Pos(‘REST’,Value)+5,Length(Value)-Pos(‘REST’,Value)-4))>10 then CurrentBytes:=strto int(copy(value,Pos(‘REST’,Value)+5,Length(Value)-Pos(‘REST’,Value)-4)); end; end; end; FTPClient.OnStatus :=@FTPStatus; procedure SockCallBackFtp(Sender: TObject; Reason: THookSocketReason; const Value: string); begin Application.ProcessMessages; case Reason of { HR_ReadCount: // для скачки begin… Подробнее »

vorvv
vorvv
05/09/2013 23:27

да в догонку totalbytes размер файла для закачки

Виталий
Виталий
10/06/2014 15:33

Доброго времени суток. Очень нужная статья. У меня небольшой вопрос.
Возникла необходимость портировать программку по отправке файлов на ftp на линукс. Перед коннектом к ftp я проверял доступность сервера TPINGSend.Ping(host). Под виндовс все работает, под линукс ping возвращает постоянно false.
Может сталкивались с таким вопросом. Заранее благодарен.

vorvv
vorvv
12/06/2014 01:47
Ответить на  Виталий

1. Я на лазарусе под Винду не пробовал
2. по вопросу пинга на лазарусе под linux делал через AProcess: TProcess;

vorvv
vorvv
12/06/2014 02:00
Ответить на  Виталий

TPINGSend.Ping(host) — только по моему (точно не помню) из под root

Виталий
Виталий
13/06/2014 00:00
Ответить на  vorvv

А программно как можно запустить TPingSend.Ping под рутом ?
Пробовал под рутом запустить программку — выдает ошибки, на форумах аналогичные ошибки объясняли именно запуском под рут

Дмитрий
Дмитрий
03/09/2014 23:29

Столкнулся с проблемой: допустим по клику на кнопке указанный текстовый файл должен отправиться на сервер (обычный хостинг) посредством ftp соединения. С прямым подключением к интернету все идеально. А если интернет идет по локальной сети, аля через прокси, программа тупо не видит интернет-подключения. Пробовал indy 10, synapse. 1. C socks не разобрался, да и вообще имеет ли оно место для интернет-подключения через локалку с другого компьютера? Допустим мне известен порт и хост, других настроек прокси не задавалось, логинов и паролей нет. Как реализовать подключение через socks? 2. Возможно ли подключение ftp через http прокси? В indy 10 например в компоненте idFTP… Подробнее »

Дмитрий
Дмитрий
04/09/2014 00:22

И сделайте, пожалуйста, гайд по установке Synapse, а то сломал голову пока ставил.

Aine
Aine
21/12/2015 17:10

Кто-то пытался победить кириллицу в названиях файлов? У меня http://Ftp.List выдает следующее: -rw-rw—- 1 admin admin 28579502 Jul 07 08:15 ??????? 2015_27.txt -rw-rw—- 1 admin admin 29083897 Jul 14 09:31 ??????? 2015_28.txt -rw-rw—- 1 admin admin 28942866 Jul 21 08:28 ??????? 2015_29.txt -rw-rw—- 1 admin admin 29020851 Jul 28 09:56 ??????? 2015_30.txt -rw-rw—- 1 admin admin 29417301 Aug 04 08:24 ??????? 2015_31.txt -rw-rw—- 1 admin admin 30110625 Aug 11 07:39 ??????? 2015_32.txt -rw-rw—- 1 admin admin 30701620 Aug 18 08:18 ??????? 2015_33.txt -rw-rw—- 1 admin admin 29872637 Aug 26 13:26 ??????? 2015_34.txt -rw-rw—- 1 admin admin 30502159 Sep 01 08:18… Подробнее »