Сегодня рассмотрим работу с ещё одним сетевым протоколом с использованием библиотеки Synapse – File Transfer Protocol (FTP).
Давно уже собирался написать про него, но всё как-то было лень :) Сегодня решил всё-таки выкроить немного времени и разобраться с работой с FTP-протоколом в Synapse. Для начала я решил немного поиздеваться над FTP-шником своего блога и написать небольшую программку, реализующую основные операции: логин, чтение списка каталогов, загрузка на сервер, скачивание с сервера и т.д. Поэтому сегодня рассмотрим рабочий пример, а в конце поста я дам ссылку на страничку описания класса TFTPSend.
Как Вы уже поняли из введения к посту, работа с FTP в Synapse организуется через использование экземпляров класса TFTPSend, который находится в модуле ftpsend.pas. Поэтому можете запускать Delphi и смело подключать этот модуль в uses.
Вначале накидаем компоненты на форму. Я решил сделать главную форму приложения такой:
На форме расположены:
- 4 Edit’а – для определения параметров подключения;
- 2 кнопки TButton – для коннекта и дисконнекта (хотите – сделайте одну для обеих операций – это не суть)
- 1 ListView для вывода содержимого текущей директории
- 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;
Запустим программу и проверим работу:
Остается только определиться как скачивать/закачивать файлы.
Для примера, предлагаю бросить на форму 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 и др.
|
Есть ли докачка в этом компоненте? Как её реализовать?
Отличная статья, побольше таких надо! Супер полезно и доступно!
вопрос, если работаешь через прокси.
Есть возможность использовать данный модуль? Чтобы писать что-то вроде:
FTPClient.Proxy:=’10.32…’
Михаил, по идее возможно, но сам так никогда не работал. Попробуйте, если получится, то отпишитесь плз — другим посетителям эта инфа тоже будет полезна
Спасибо за интересный и полезный блог.
Подскажи пожалуйста, как с Tftpsend работать через socks5.
а можно ли как нибудь в процессе загрузки файла узнавать текущий объем закачанных данных (ну процент загрузки файла)
sergey, по-моему можно — надо посмотреть события сокета.
Пришлось по работе бросать файлы на ФТП сервер с SSL. Вроде удалось решить проблему благодаря вашему примеру, но с некоторыми модификациями. В раздел USES добавил плагин ssl_openssl и в свойствах создаваемого клиента FTPClient.FullSSL := True; Но это потребовало тащить с приложением еще две DLL от OpenSSL Прочитал в Синапсе, что можно использовать плагин ssl_streamsec с библиотекой OpenStrSecII. В этом случае можно избавится от ДЛЛ Нашел такую библиотеку, но все мои потуги не дали результатов. Я использую древнюю Дельфи5. Не компилируется ssl_streamsec. Не знает функции Sleep. Для компиляции добавил в USES модуль Windows. Но попытка логина к ФТП серверу стабильно выдает… Подробнее »
vvkhr, я таких примеров, к сожалению, никогда не встречал — не было необходимости
if OpenDialog1.Execute then
begin
FTPClient.DataStream.LoadFromFile(OpenDialog1.FileName);//записали содержимое файла в поток
FTPClient.StoreFile(ExtractFileName(OpenDialog1.FileName),false);//сохранили на сервер
FTPClient.List(FTPClient.GetCurrentDir,false);//прочитали новое содержимое директории
{перечисляем имена директорий и файлов}
end;
Как показать в прогресс баре???
Надо написать обработчик события у свойства Sock. Более подробно о событиях тут (не важно, что я даю ссылку на работу с THTTPSend. С TFTPSend работать надо точно так же).
Не понимаю, передаю таким образом (как описано в материале выше) текстовый файл на фтп, он там успешно появляется..но, почему то пустой( как справиться с проблемой?
собственно, сам код:
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;
а так не пробовали делать:
...
FTPClient.DataStream.LoadFromFile(abs_name);//записали содержимое файла в поток
FTPClient.DataStream.Position:=0;
FTPClient.StoreFile(output_file, false);//сохранили на сервер
...
Я сейчас исходник Synapse посмотреть не могу, но по-моему, в StoreFile позицию в потоке никто не меняет, а надо бы.
Никто так и не знает как делать докачку файла
при закачке/скачке?
Вроде бы раскопал 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… Подробнее »
да в догонку totalbytes размер файла для закачки
Доброго времени суток. Очень нужная статья. У меня небольшой вопрос.
Возникла необходимость портировать программку по отправке файлов на ftp на линукс. Перед коннектом к ftp я проверял доступность сервера TPINGSend.Ping(host). Под виндовс все работает, под линукс ping возвращает постоянно false.
Может сталкивались с таким вопросом. Заранее благодарен.
Виталий, про Linux ничего не могу подсказать. У меня его сейчас даже под рукой нет.
1. Я на лазарусе под Винду не пробовал
2. по вопросу пинга на лазарусе под linux делал через AProcess: TProcess;
TPINGSend.Ping(host) — только по моему (точно не помню) из под root
А программно как можно запустить TPingSend.Ping под рутом ?
Пробовал под рутом запустить программку — выдает ошибки, на форумах аналогичные ошибки объясняли именно запуском под рут
Столкнулся с проблемой: допустим по клику на кнопке указанный текстовый файл должен отправиться на сервер (обычный хостинг) посредством ftp соединения. С прямым подключением к интернету все идеально. А если интернет идет по локальной сети, аля через прокси, программа тупо не видит интернет-подключения. Пробовал indy 10, synapse. 1. C socks не разобрался, да и вообще имеет ли оно место для интернет-подключения через локалку с другого компьютера? Допустим мне известен порт и хост, других настроек прокси не задавалось, логинов и паролей нет. Как реализовать подключение через socks? 2. Возможно ли подключение ftp через http прокси? В indy 10 например в компоненте idFTP… Подробнее »
И сделайте, пожалуйста, гайд по установке Synapse, а то сломал голову пока ставил.
Кто-то пытался победить кириллицу в названиях файлов? У меня 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… Подробнее »