Создаём свой GetRight

== Постановка задачи ==
А задача наша проста как угол дома - сесть за комп и максимум за полчаса сообразить себе собственный GetRight. Конечно, он не будет производить докачку после дисконнекта, качать в заданное тобой время, не сможет качать несколько файлов сразу... но зато он сможет качать файлы по ftp и http, для начала совсем неплохо. Соображать прогу будем на Delphi. Ну что, задача ясна? От винта! 
== Делаем фейс ==
Запускай Delphi, желательно в версии 4 или 5. Перед тобой раскроется целехонькая и нетронутая (хе-хе, пока) форма. На ней мы и будем мутить. Что, ты не знаешь, что такое форма и где она там перед тобой раскрывается? Тогда позырь на монитор - вон она, большой серый прямоугольник в центре. И вообще, я не буду тебе щас про дельфийский интерфейс шибко подробно рассказывать. Лучше сразу за дело! Сейчас мы немного покликаем мышом и потаскаем. Итак, начнем: сначала нужно изменить название формы. Она сейчас называется Form1, а на кой тебе такое название? Это ж название окна твоей проги. Изменить! Кликай по форме, она становится активной, теперь смотри налево - там Object inspector, фича для конфигурирования разных свойств. Свойство, ответственное за название, называется Caption, ищи его в Object Inspector'е и нажимай на него. В белом окошке вводи что-то типа "Крутая программа-качалка". Ну как, все понятно? Позырь вон на скриншот, там Object Inspector есть.
Теперь смотри над формой - там палитра компонентов. На закладке Standard кликай мышом по букве А. Эта буква А - ни что иное, как Метка (Label). Нам она нужна, чтобы писать на форме. Кликай мышом по ней, а потом по форме, куда кликнешь на форме - там она и будет. Она сейчас выделена (в черных квадратиках вся), посему Object Inspector отображает ее свойства. Меняй Caption (в нем напиши "Введи адрес файла сюда: ") и Font (он находится ниже, кликни на нем, а потом на трех точках; я ставлю 10-ый Tahoma полужирный).
Добавь еще одну метку (поставь ее ниже), в ней 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://. Но ты теперь можешь не мучаться и кодить спокойно, а если что не так - мыль мне, я постараюсь ответить на твои вопросы. Удачи!
Source: http://www.realcoding.net/
ID: 03587
Category:Связь
Category:Web
Category:Статьи
Category:Учебники