Создаем свой GetRigrht

Постановка задачи

А задача наша проста как угол дома - сесть за комп и максимум за полчаса сообразить себе собственный GetRight. Конечно, он не будет производить докачку после дисконнекта, качать в заданное тобой время, не сможет качать несколько файлов сразу... но зато он сможет качать файлы по ftp и http, для начала совсем неплохо. Соображать прогу будем на Delphi. Ну что, задача ясна? От винта!

Делаем фейс

Запускай Delphi, желательно в версии 4 или 5. Перед тобой раскроется целехонькая и нетронутая (хе-хе, пока) форма. На ней мы и будем мутить. Что, ты не знаешь, что такое форма и где она там перед тобой раскрывается? Тогда позырь на монитор - вон она, большой серый прямоугольник в центре. И вообще, я не буду тебе щас про дельфийский интерфейс шибко подробно рассказывать. Лучше сразу за дело! Сейчас мы немного покликаем мышом и потаскаем. Итак, начнем: сначала нужно изменить название формы. Она сейчас называется Form1, а на кой тебе такое название? Это ж название окна твоей проги. Изменить! Кликай по форме, она становится активной, теперь смотри налево - там Object Inspector, фича для конфигурирования разных свойств. Свойство, ответственное за название, называется Caption, ищи его в Object Inspector'е и нажимай на него. В белом окошке вводи что-то типа "Крутая программа-качалка". Ну как, все понятно? Позырь вон на скриншот, там Object Inspector есть.

Теперь смотри над формой - там палитра компонентов. На закладке Standard кликай мышом по букве А. Эта буква А - ни что иное, как Метка (Label). Нам она нужна, чтобы писать на форме. Кликай мышом по ней, а потом по форме, куда кликнешь на форме - там она и будет. Она сейчас выделена (в черных квадратиках вся), посему Object Inspector отображает ее свойства. Меняй Caption (в нем напиши "Введи адрес файла сюда: ") и Font (он находится ниже, кликни на нем, а потом на трех точках; я ставлю 10-ый MS Sans Serif полужирный). Добавь еще одну метку (поставь ее ниже), в ней Caption поставь "Сохранить файл сюда: ", ну и шрифт поставь аналогичный. В третьей метке поменяй шрифт и сотри все в Caption, здесь мы будем выдавать сообщения по ходу загрузки. Теперь добавь два Edit'а (справа от метки в палитре компонентов). Первый поставь напротив первой метки справа (это будет для ввода адреса), второй - напротив второй метки справа (это для сохранения). У обоих сотри текст (там написано Edit1, Edit2, на фиг оно надо), для этого выдели (клик по нему мышом) и стирай текст в свойстве Text. Затем кинь на форму две кнопки (через одну справа от Edit'а в палитре компонентов), первую назови "Закачать", вторую - "Закрыть" (это все свойства Caption кнопок). Потом открой закладку Internet (для Delphi 4) или FastNet (для Delphi 5) палитры компонентов. Помести на форму компоненты NMFTP и NMHTTP, это для закачки. Они не будут видны в готовой программе, посему тыкай их куда хочешь. Уфф, можешь сохраняться. Дави File -> Save All. Форму обзови main, например, а проект - downloader. Посмотри, что у меня получилось.

Готовимся кодить

Увы, программирование состоит не только из кликанья мышой и редактирования свойств. Приходится и кодить, и сейчас мы вплотную приблизились к этому. Но начнем с простого. Кликни два раза по кнопке "Закрыть". Опа! На экране появилось следующее:

procedure TForm1.Button2Click(Sender: TObject);
begin
end;

и твой курсор мигает между begin и end. Это - обработчик события OnClick для кнопки "Закрыть", и все, что ты напишешь между begin и end, будет выполняться при клике по этой кнопке. А нам нужно, чтобы прога закрывалась, посему пишем

procedure TForm1.Button2Click(Sender: TObject);
begin
NMFTP1.Disconnect ; // разрываем связь по фтп, если она установлена
NMHTTP1.Disconnect ; // разрываем связь по хттп, если она установлена
Close ; // Закрываем прогу
end ;

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

Кстати, после // в Delphi до конца строки идет комментарий, его она не учитывает при компиляции. Комментарии для тебя, чтобы понятнее было, не нужно их переписывать. Обрати внимание, там написано Button2Click, а не "Закрыть" Click. Button2 - это рабочее имя кнопки для взаимодействия с программой (как в вышеописанном примере), а Caption - это всего лишь надпись на кнопке. Все имена компонентов находятся в их свойстве Name, можешь посмотреть в Object Inspector'е. Теперь кликни два раза по первому Edit'у, появляется нечто похожее на обработчик для кнопки:

procedure TForm1.Edit1Change(Sender: TObject) ;
begin
end ;

Тут вместо OnClick мы видим OnChange - все, что находится между begin и end, будет выполняться, когда в Edit'е что-то напишут. Мы изменим Tag (свойство Edit'а, некоторое число, по умолчанию 0), это нам понадобится потом, для проверки заполнения всех полей.

procedure TForm1.Edit1Change(Sender: TObject) ;
begin
Edit1.Tag := 1 ; // присвоить тагу первого эдита значение 1
end ;

Аналогичную операцию необходимо проделать и со вторым эдитом, только там нужно писать:

Edit2.Tag := 1 ;

Не забывай об именах! Вот и все с подготовкой, а теперь начинается...

Реальный кодинг

Да, именно он. Читай внимательнее и вникай. Перейдем к нашей главной кнопке - "Закачать". Кликай по ней два раза и создавай обработчик, далее вписывай код, чтобы получилось вот что:

procedure TForm1.Button1Click(Sender: TObject) ;
begin
Label3.Caption := '' ; // очищаем метку для сообщений
if ( Edit1.Tag = 1 ) and ( Edit2.Tag = 1 ) and ( Edit1.Text <> '' )
and ( Edit2.Text <> '' ) then // проверка данных
begin
// данные введены, выполнять действия
end
else Label3.Caption := 'Введи все данные, чувак!' // не все данные
end ;

Что есть что: сначала очищаем метку, просто присваиваем ее Caption'у пустое место (сначала она, правда, и так пустая, но потом будет полная, поэтому очищаем), затем идет стандартный оператор if then else, используем этот оператор для проверки, все ли поля заполнены - помнишь, мы тагам единицы присваивали? Так вот, теперь и проверяем - если чувак поля не заполнил, то таги - "0", и проверка не пройдет. Но юзверь мог ввести дату, а потом все стереть - вот для этого и нужна проверка значений эдитов на '' - если там пустое место (''), то проверка не пройдет. Дальше просто: если проверка прошла - гоним далее, нет - пишем в метке "Введи все данные, чувак!". Ну как, врубаешься? Если нет, просто пиши код, но все-таки старайся понять.

Продолжаем разговор. Нам нужно узнать, по фтп загружать или по хттп. Для этого нужно знать, что впереди: ftp:// или http://. Чтобы вытянуть это из оригинального адреса, проведем ряд извращений со строками. Дописывай код:

procedure TForm1.Button1Click(Sender: TObject) ;
begin
Label3.Caption := '' ; // очищаем метку для сообщений
if ( Edit1.Tag = 1 ) and ( Edit2.Tag = 1 ) and ( Edit1.Text <> '' )
and ( Edit2.Text <> '' ) then // проверка данных
begin // данные введены, выполнять действия
addr := Edit1.Text ; // сохраняем адрес в переменную
serv := Copy( addr , 1 , 6 ) ; // копируем 6 символов из адреса в
// переменную serv
if serv = 'ftp://' then // впереди ftp://
begin
// качаем по фтп
end
else
if serv = 'http:/' then // впереди http:/
begin
// качаем по хттп
end
else Label3.Caption := 'Что за корявый адрес?' ;
end
else Label3.Caption := 'Введи все данные, чувак!' // не все данные
end ;

Сначала мы сохранили адрес из первого эдита в переменную addr, затем в переменную serv мы из переменной addr копируем 6 символов. Используем функцию Copy. В скобках идут параметры - сначала пишем переменную, из которой копировать, потом номер символа, с которого начинать, ну и потом сколько символов копировать. Всю скопированную бурду сохраняем в переменной serv, теперь проверяем: если серв равен ftp://, то качать будем по фтп, а если http:/ - по хттп. Ну а если серв другой, то адрес корявый - это и напишем в метке. Кстати, переменные serv и addr еще не определены, и программа будет ругаться (а работать не будет). Надо их определить, иди в самый верх кода и там ищи слово var. Вот после этого слова и допиши переменные, заодно добавь еще несколько - они нам потом пригодятся. Вот так:

var
serv , addr , host , dir : String ;

String - это строка, соответственно, все эти переменные - строки. Уфф! Теперь последние штрихи на этой стадии - для скачки по фтп нужно сначала соединиться с хостом (сервером), а потом уже скачивать файло. Нужно разбить адрес на хост и собственно адрес файла, а это опять извращения со строками. Дописывай:

procedure TForm1.Button1Click(Sender: TObject) ;
begin
Label3.Caption := '' ; // очищаем метку для сообщений
if ( Edit1.Tag = 1 ) and ( Edit2.Tag = 1 ) and ( Edit1.Text <> '' )
and ( Edit2.Text <> '' ) then // проверка данных
begin // данные введены, выполнять действия
addr := Edit1.Text ; // сохраняем адрес в переменную
serv := Copy( addr , 1 , 6 ) ; // копируем 6 символов из адреса в
// переменную serv
if serv = 'ftp://' then // впереди ftp://
begin
Delete( addr , 1 , 6 ) ; // удаляем первые 6 символов из
//адреса
host := Copy ( addr , 1 , ( Pos( '/' , addr ) - 1 ) ) ;
// находим хост
Delete( addr , 1 , ( Pos( '/' , addr ) - 1 ) ) ;
dir := addr ;
// находим путь к файлу
// качаем по фтп
end
else
if serv = 'http:/' then // впереди http:/
begin
// качаем по хттп
end
else Label3.Caption := 'Что за корявый адрес?' ;
end
else Label3.Caption := 'Введи все данные, чувак!' // не все данные
end ;

Итак, сначала функцией Delete стираем первые 6 символов из адреса. Функция берет строку, из которой стирать, символ, с которого начинать стирать, количество стираемых символов - все очень похоже на Copy. Затем в переменную host копируем адрес сервака, но вместо количества символов там стоит конструкция типа

(Pos( '/' , addr ) -1). Все путем! Функция Pos находит положение символа / в строке addr и выдает число, которое показывает, какой этот символ по счету. Но нам его копировать не надо, поэтому и отнимаем единицу. Теперь, если адрес файла ftp://my.host.com/file.exe, то адрес сервера будет my.host.com. Дальше стираем из адреса хост, и остается адрес файла - его и присваиваем переменной dir. Все, подготовка закончена, все данные обработаны, сохраняйся.

Кодим скачку по фтп

Обработаем теперь докачку по фтп. Ниже идущий код пиши там, где надпись:

// качаем по фтп.

Сначала поработаем с кнопками, дописывай код:

Edit1.Enabled := false ;
Edit2.Enabled := false ; // вырубаем эдиты
Button1.Enabled := false ; // выключаем кнопку "Закачать"

Тут, я думаю, все понятно, прописываем закачку:

NMFTP1.Host := host ;
NMFTP1.UserID := 'anonymous' ;
NMFTP1.Password := '' ;
Label3.Caption := 'Подключаемся ... ' ;
NMFTP1.Connect ;
NMFTP1.Mode( MODE_IMAGE ) ;
Label3.Caption := 'Начинаем качать ...' ;
NMFTP1.Download( dir , Edit2.Text ) ;
Label3.Caption := 'Ура !!!' ;
Label3.Caption := 'Отключаемся ...' ;
NMFTP1.Disconnect ;

Тут тоже все понятно - соединяемся, скачиваем, отсоединяемся. Download берет себе сначала адрес файла в Инете, а потом адрес, куда его сохранить на диске. Вот и все. Обрабатываем кнопки:

Button1.Enabled := true ; // включаем кнопку "Закачать"
Edit1.Enabled := true ;
Edit2.Enabled := true ; // врубаем эдиты
Edit1.Clear ;
Edit2.Clear ; // очищаем эдиты

Поработай немного мышом - добавим несколько комментариев. Выдели компонент NMFTF1 у себя на форме, затем кликни в Object Inspector'е на вкладку Events (кликай на OnConnect, затем на белое место справа - два раза).

Пиши:

procedure TForm1.NMFTP1Connect(Sender: TObject);
begin
Label3.Caption := 'Подключено успешно!!!' ;
end;

Теперь, когда соединение установлено, прога выдаст в метку сообщение. Кликай по OnConnectionFailed. Пиши:

procedure TForm1.NMFTP1ConnectionFailed(Sender: TObject);
begin
Label3.Caption := 'Ошибка!!! Не могу соединиться!' ;
end;

Ну и так и далее, там все прозрачно, пофантазируй немного.

Все, обработка фтп закончена.

Кодим скачку по http

После скачки по фтп это совсем легко, посему отдыхай. Код пиши вместо строки:

// качаем по хттп .

А код следующий:
Edit1.Enabled := false ;
Edit2.Enabled := false ; // вырубаем эдиты
Button1.Enabled := false ; // выключаем кнопку "Закачать"

Обрабатываем кнопки и эдиты, как и при скачке по фтп.

Label3.Caption := 'Подключаемся ... ' ;
Delete(addr, 1, 7) ;

В переменной addr у нас адрес, помнишь? Так вот, удаляем из него кусок http:// - это ОЧЕНЬ важно. Почему? Потом объясню. Теперь, собственно, скачка:

NMHTTP1.InputFileMode := true ;
NMHTTP1.Body := Edit2.Text ;
NMHTTP1.Get( addr ) ; // качаем

Опять обрабатываем кнопки:

Button1.Enabled := true ; // включаем кнопку "Закачать"
Edit1.Enabled := true ;
Edit2.Enabled := true ; // врубаем эдиты
Edit1.Clear ;
Edit2.Clear ; // очищаем эдиты

С кодом все, теперь осталось добавить несколько событий, как и при скачке по фтп. Кликай на компоненте NMHTTP1 на форме, и в Object Inspector'е выбирай закладку Events. А дальше фантазируй: напиши что-нибудь при OnConnect, OnConnectionFailed, OnDisconnect. А вообще, корректная обработка ошибок (типа OnConnectionFailed) - это гимор, поэтому особо не забивай себе голову.

Последние штрихи

Чего-то не хватает... Правильно! Не хватает прогресс-бара - этой синей полоски с процентами! Но это не проблема, сейчас сделаем. Открывай закладку Win32 палитры компонентов, хватай компонент ProgressBar и лепи его на форму (чтобы посмотреть, как его прилепил я, позырь на скриншот готовой проги). Теперь выделяй компонент NMFTP1 и открывай в Object Inspector'е закладку Events. Ищи OnPacketRcvd. Создавай обработчик (клик по OnPacketRecvd, два по пустому месту справа от него). Там пиши следующий код:

procedure TForm1.NMFTP1PacketRecvd(Sender: TObject);
begin
ProgressBar1.Position := Round(NMFTP1.BytesRecvd*100/NMFTP1.BytesTotal) ;
Label3.Caption := 'Получено ' + IntToStr(NMFTP1.BytesRecvd) + ' байт из ' + IntToStr (
NMFTP1.BytesTotal ) ;
end;

Строки разрывать не надо, просто они длинные и не помещаются.

Теперь, когда прога будет что-то качать, синяя строчка будет ползти, а в метке будет написано, сколько байт уже получено. Все эти действия необходимо повторить и для NMHTTP1, только NMFTP1 в коде замени на NMHTTP1. После завершения загрузки очистим ProgressBar - для этого в конце фтп и хттп фрагментов - там, где мы открывали эдиты и очищали их - допиши следующую строку:

ProgressBar1.Position := 0 ; // очищаем прогресс-бар

Теперь сохраняй все и компилируй (дави на F9) - получишь вполне работоспособную прогу-качалку, пользуйся.

Последнее слово

Так вот, чтобы написать эту прогу, мне пришлось основательно помучаться: я не знал, ни как закачать файлы по фтп, ни как закачать его по хттп. Но если с фтп, перерыв борландовский хелп и примеры, я разобрался, то хттп постоянно глючил, выдавал битый файл. Я написал в десяток ньюсгрупп - как русских, так и забугорных, задавал вопросы на бордах крутых дельфовских сайтов, я писал программерам, я написал в службу поддержки разработчика компонента NMHTTP ... И что ты думаешь, кто-нибудь посоветовал что-нибудь путевое? Фиг!

Я дошел сам. А дело было в мелочи: я делал все правильно, но писал

NMHTTP1.Get('http://www.host.com/file.zip') ;

А нужно было

NMHTTP1.Get('www.host.com/file.zip') ;

Вот почему нужно выбрасывать часть http://. Но ты теперь можешь не мучаться и кодить спокойно, а если что не так - мыль мне, я постараюсь ответить на твои вопросы. Удачи!



Опубликовал admin
11 Июн, Среда 2003г.



Программирование для чайников.