(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Скачиваем файлы из интернета при помощи Delphi

Источник: delphi
Вадим К.

Задача: скачать файл по http в указанную папку с использованием потока.

Делаем форму

Бросаем на форму два TEdit, TProgressBar, одну кнопку и TSaveDialog.

Делаем форму

Для кнопки пишем маленький обработчик:

//Этой строкой мы скопируем имя файла SaveDialog1.FileName:=copy(Edit1.Text,LastDelimiter('\⁄',Edit1.Text)+1,maxint);
if SaveDialog1.Execute then
  Edit2.Text:=SaveDialog1.FileName;

Теперь на форму добавим IdHTTP и кнопку (Button2) с надписью "начать закачку".

Делаем поток

С обработчиком пока повременим, а напишем самое сложное - класс для потока.

{$R *.dfm}
//---------------------------------------
type
  TDownLoader = class(TThread)
  protected
    procedure Execute; override;
  public
    property URL:string read FURL write FURL;
    property ToFolder:string read FToFolder write FToFolder;
end;

Первые две строки сделаны для того, чтобы было видно, где вписать код. И нажимаем Ctrl+Shift+C. Delphi допишет немного кода. Он теперь будет выглядеть так:

type
  TDownLoader = class(TThread)
  private
    FToFolder: string;
    FURL: string;
  protected
    procedure Execute; override;
  published
  public
    property URL:string read FURL write FURL;
    property ToFolder:string read FToFolder write FToFolder;
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SaveDialog1.FileName:=copy(Edit1.Text,LastDelimiter('\⁄',Edit1.Text)+1,maxint);
  if SaveDialog1.Execute then
    Edit2.Text:=SaveDialog1.FileName;
end;

{ TDownLoader }

procedure TDownLoader.Execute;
begin
  //здесь мы начнём писать код работы
end;

Компонент idHTTP был брошен на форму только с одной целью - чтобы Delphi добавила все заголовочные файлы в uses. Потом его можно будет удалить. Но можно и самостоятельно вписать в uses файл idHTTP.

Главный код потока

Итак, код обработчика:

procedure TDownLoader.Execute;
var
  http:TIdHTTP;
  str:TFileStream;
begin
  //Создим класс для закачки
  http:=TIdHTTP.Create(nil);
  //каталог, куда файл положить
  ForceDirectories(ExtractFileDir(ToFolder));
  //Поток для сохранения
  str:=TFileStream.Create(ToFolder, fmCreate);
  try
    //Качаем
    http.Get(url,str);
  finally
    //Нас учили чистить за собой
    http.Free;
    str.Free;
end;

end;

Помните, что в этой процедуре нельзя напрямую обращаться к компонентам формы и другим потокам. Это делается специальным образом, который называется синхронизацией.

Запускаем поток

И наконец, обработчик для кнопки:

procedure TForm1.Button2Click(Sender: TObject);
var d:TDownLoader;
begin
  //Создадим класс потока.
  //Поток для начала будет остановлен
  d:=TDownLoader.Create(true);
  //Передадим параметры потоку
  d.URL:=Edit1.Text;
  d.ToFolder:=Edit2.Text;
  //Поток должен удалить себя по завершению своей работы 
  d.FreeOnTerminate:=true;
  //И запустим его на закачку.
  d.Resume;
  //Теперь с процедуры мы выйдем, но поток работает
  //и живёт своей жизней
end;

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

Дополнительные возможности

Добавим для начала уведомление о закачке. Добавим в public часть формы добавим строку:

public
  { public declarations }
  procedure thrTerminate(Sender:TObject);
end;

и нажмём Ctrl+Shift+C.

Появится новый обработчик, который мы дополним одной строкой. Я вывожу просто сообщение о готовности. Помните, эта процедура будет вызваться, когда поток выполнит всю свою работу (завершится процедура Execute). Только в этой процедуре можно одновременно обращаться к компонентам формы и данным потока.

procedure TForm1.thrTerminate(Sender: TObject);
begin
  ShowMessage('Готово');
end;

И добавим её вызов в обработчике кнопки запуска:

//Поток должен удалить себя по завершению своей работы
d.FreeOnTerminate:=true;
d.OnTerminate:=thrTerminate;

Делаем прогресс

Теперь у нас осталась ещё одна проблема - оживить прогресс-бар. Но здесь нас подстерегает один момент: с потока нельзя просто так обращаться к компонентам формы. Точнее, правило звучит так: с одного потока нельзя обращаться к данным другого потока (переменным, коду) без специальных методов. Таких методов есть два. Первый - мы останавливаем один поток, а второй на это время получает доступ к его переменным. Либо второй поток просит первый исполнить какой-то код, а сам на это время засыпает.

Способ два, которым мы и воспользуемся - это посредник. Мы шлём сообщение посреднику, чтобы он сообщил другому потоку (а может и группе), чтобы он что-то сделал. Этот способ хорош тем, что поток может обрабатывать сообщения не по принуждению, а по возможности. То есть сообщения стают в очередь. В качестве посредника мы выберем саму среду Windows.

Итак, Windows при посылке сообщения позволяет передавать два целочисленных параметра. Первый мы будем использовать как идентификатор действий, второй - как дополнительный параметр.

Поехали дальше. После uses перед Type вставим строку:

const
  MY_MESS = WM_USER + 100;

А в объявлении формы добавим новый метод:

procedure MyProgress(var msg:TMessage);message MY_MESS;

И заветное Ctrl+Shift+C

В свежесозданном обработчике пишем такое:

procedure TForm1.MyProgress(var msg: TMessage);
begin
  case msg.WParam of
    0: begin ProgressBar1.Max:=msg.LParam;ProgressBar1.Position:=0; end;
    1: ProgressBar1.Position:=msg.LParam;
  end;
end;

То-есть, если передали тип операции 0 - значит нужно инициализировать прогресс. Передали 1 - нужно выставить позицию. Как именно - указано в другом параметре (msg.LParam).

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

procedure TDownLoader.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Integer);
begin
  PostMessage(Application.MainForm.Handle,MY_MESS,1,AWorkCount);
end;

procedure TDownLoader.IdHTTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
AWorkCountMax: Integer);
begin
  PostMessage(Application.MainForm.Handle,MY_MESS,0,AWorkCountMax);
end;

Заключение

Естественно, есть ещё несколько способов всё синхронизировать. Но такой способ мне кажется очень простым и надёжным, так как не будет блокировок, сообщения будут обрабатываться по мере возможности (по мере сил :-)).

В сопутствующем архиве вы найдёте полный рабочий пример. Он будет компилироваться на Delphi 2006 и Indy 10. На 7 Delphi сходу может не скомпилироваться, но если вы будете делать вручную и немного думать, то всё заработает. Причина - с Delphi 7 поставляется более старая версияIndy.

Ссылки по теме

Файлы для загрузки


 Распечатать »
 Правила публикации »
  Обсудить материал в конференции Embarcadero » [1]
Написать редактору 
 Рекомендовать » Дата публикации: 20.10.2009 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Обновление с КОМПАС-3D V16 Home до КОМПАС-3D v17 Home
Stimulsoft Reports.Ultimate Single License Includes one year subscription, source code
Quest Software. TOAD for Oracle Edition
Panda Internet Security - ESD версия - на 1 устройство - (лицензия на 1 год)
SAP® Crystal Dashboard Design Departmental 2016 WIN INTL NUL
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Delphi - проблемы и решения
Краткие описания программ и ссылки на них
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
Обсуждения в форумах
Пишу программы на заказ профессионально (2186)
Пишу программы на заказ на языках Pascal (численные методы, списки, деревья, прерывания) под...
 
Пишу программы на заказ для студентов (176)
Пишу для студентов на с, с++, паскаль в средах ms visual studio, qt, builder, borland c, delphi....
 
Ищу программиста для написания программы (15)
Ищу программиста ,владеющего Вижуал Бэйсик и программированием в Экселе, для написания...
 
И я там был (2)
И я там был, мед пиво пил, по усам текло, а в рот не попало.
 
Пишу программы на Lazarus (19)
Предлагаю разработку программ на заказ. Примеры программ: www.itproportal.ru
 
 
 



    
rambler's top100 Rambler's Top100