ВСЕ ЗАПИСИ
Статьи,заметки
Загрузка файлов с докачкой, с использованием компонента Indy
Обновлено: январь 2021
Добавил рабочий исходник для Indy 10, ссылка внизу страницы
Indy (Internet Direct) - компоненты для удобной работы с популярными интернет-протоколами. Эти компоненты часто используют программисты на Дельфи в своих разработках. Причина такой популярности Indy понятна, - Indy по умолчанию встроен в Delphi 7, многие начинали свой путь в программирование именно через Паскаль и Дельфи, под Indy в сети можно найти множество хороших примеров и готовых исходников.
Но вот, как мне пришлось убедиться, если вы хотите сделать на Indy свой загрузчик файлов, поддерживающий докачку после обрыва соединения, то готовых решений в сети вы не найдёте. Обсуждение этого вопроса можно найти на многих форумах по программированию, и во всех случаях, которые мне известны, ветка обсуждения обрывается на том, что автор топика отписывается, что мол, попробовал, все варианты, ничего не получается, ну его нафиг, этот глючный Indy, буду использовать другие компоненты; или пишет, сделал, всё заработало, но что интересно, никто так и не показывает рабочий код. А потом, вопрос, как использовать Indy для загрузки файлов, появляется на форумах снова и снова.
Поэтому я решил выложить здесь свой вариант, который я использовал в одном из своих проектов, думаю, что многим он будет полезен. Код 100% рабочий, легко адаптируемый, используется версия Indy 9, та, что установлена в Delphi 7 изначально. Следует иметь в виду что , из-за ограничений 9-й версии, этот код не может быть использован для загрузки файлов размером более 2Гб, но сейчас вряд ли где можно найти прямые ссылки на такие большие файлы, такой контент давно уже можно встретить только в торрентах, а вот для скачивания например, видео с youtube, этот код можно использовать, самые большие файлы, которые мне попадались на youtube весили 1,5 - 1,8 Гб.
Чтобы загрузить файл, нужно прежде всего создать/открыть файл, либо MemoryStream, куда будут сбрасываться данные, инициализировать компонент IdHTTP, и воспользоваться методом Get.
...................
var
http: TIdHTTP;
fs: TFileStream;
s,url: string;
begin
s:='file.ext';
url:='http://site.domain/file.ext';
fs:=TFileStream.Create(s,fmCreate or fmShareDenyNone);
http:=TIdHTTP.Create(nil);
http.Get(url,fs);
FreeAndNil(http);
FreeAndNil(fs);
end;
..........................
Этого кода достаточно, чтобы открыть адрес http://site.domain/file.ext и сохранить по этой ссылке файл file.ext на жёсткий диск.
Но.. Файл-то скачается, но если он достаточно большого размера, то пока закачка не завершится, приложение повиснет и перестанет отвечать на другие запросы (чтобы этого не происходило, процесс закачки обычно выносят в другой поток, но для этого придется усложнять код). Если закачку прервать, то на диске останется файл того же размера, который занимал бы полностью закачанный файл. А если запустить закачку снова, то файл придётся загружать с самого начала.
Чтобы было возможно докачивать незавершённые файлы, нужно знать их размер. Размер файла можно узнать с помощью свойства TIdHTTP.Response.ContentLength - возвращаемое значение - размер файла в байтах. Определяем размер незавершённого файла, который лежит на диске, вычисляем, сколько байт ещё осталось докачать, и с помощью свойств TIdHTTP.Request.ContentRangeStart и TIdHTTP.Request.ContentRangeEnd задаем размер части, которую нужно догрузить.
В моём коде компонент TIdHTTP создаётся динамически (его не нужно бросать на форму при создании проекта), закачка производится в цикле, в один период цикла программа получает сегмент данных размером 200 Кб (как это сделано в известном менеджере закачек - FlashGet) и сразу записывает их в файл, при этом программа не успевает зависать, что позволяет осуществлять закачку в основном потоке программы, без написания отдельного потока для загрузчика. Размер файла на диске, также увеличивается пропорционально полученным данным, и в случае преждевременной остановки загрузки, зная полный размер файла, и прочитав размер файла на диске можно легко определить с какого места нужно докачивать.
В коде дополнительно используются две функции function online ,которая проверяет, есть ли подключение к интернету, в момент старта закачки, и function BytesToMbytes ,которая используется для вывода количества скачанных данных в реальном времени, - размер файла по ссылке и количество скачанного в мегабайтах с точностью до сотых, выводится на метки формы, я использовал их вместо прогрессбара, но при желании можно его добавить на форму.
Следует обратить внимание, что после завершения загрузки показания счётчика загруженных данных будут немного отличаться от размера файла по ссылке в большую сторону, это нормально, такое наблюдается практически во всех менеджерах загрузки, вот например, что нам покажет сам виндовский проводник

И напоследок расскажу ещё об одном глюке программы, который мне так и не удалось устранить, но по-видимому здесь может помочь только смена версии Indy на более свежую, но пока я не могу проверить этот код на 10-й версии Indy. На работоспособности кода этот глюк не отражается, и на том спасибо:)
Проявляется это так: в момент, когда уже загружен последний байт IdHTTP выдаёт ошибку, что '*/xxx is not a valid integer value' , где ххх - полный размер в байтах файла по ссылке, то есть параметр TIdHTTP.Response.ContentLength ,получается что в момент завершения Indy вместо числового значения, выдаёт его строкой, вместе с символами '*/' . Я пробовал даже не использовать Response.ContentLength , - файл всё равно нормально докачивается до конца,просто мы не увидим размер файла.но сообщение об ошибке всё-равно выдаётся. Пробовал получить все нужные мне значения в строковом виде, отфильтровать лишние символы самостоятельно и перевести необходимые параметры в числовые, методом TIdHTTP.Response.RawHeaders. GetText , но всё напрасно - эта ошибка неубиваема! Пришлось поставить на этот участок кода обработчик try...except ,теперь конечно, даже если произойдёт сбой во время загрузки, например, обрыв сети, программа выдаст, что закачка успешно завершена, но по счётчику данных и размеру файла на винте всё-равно можно понять, что произошла ошибка. Просто запускаем докачку с места обрыва, файл будет корректно загружен в любом случае, был ли это непредвиденный сбой или остановка загрузки вручную, именно для этого код и был разработан :)
Исходный код программы:
Скачать исходник
А вот ещё парочка исходников, которые можно применить для загрузки файлов.
Здесь используется IdHTTP, вынесенный в отдельный поток, присутствует прогрессбар для индикации, докачка не реализована. Исходник взял с http://delphi.int.ru , я адаптировал его под Indy v.9 скачать
А в этом исходнике использован компонент WinInet, закачка вынесена в отдельный поток, есть прогрессбар, докачка поддерживается. Разработан в какой-то из новых версий Delphi, но в Delphi 7 также компиллится без проблем. скачать
Сейчас уже, наверное, немногие используют Delphi 7, но я, например, не отказался от него совсем, так как приходится поддерживать старые проекты. Поэтому и этот код был доработан, с учетом того, что многие сайты сейчас работают по защищенному протоколу https:// и чтобы приложение оставалось работоспособным, его нужно адаптировать. Прежде всего добавляем на форму компонент IdSSLIOHandlerSocket(IdSSLOpenSSL), который находится на вкладке Indy I/O Handlers.И добавляем несколько строк в код, который был приведен выше:
Вот эта часть, кода, добавленные строки выделены красным:
...............
FreeAndNil(f);
http:=TIdHTTP.Create(nil);
http.Response.KeepAlive := true;
http.HandleRedirects:=true;
//-------------начало вставки
IdSSLIOHandlerSocket1:=TIdSSLIOHandlerSocket.Create(nil);
IdSSLIOHandlerSocket1.SSLOptions.Method:=sslvTLSv1;
http.IOHandler:=IdSSLIOHandlerSocket1;
//-------------конец вставки
http.Head(url);
...............
И если вы используете function online, как в моем примере, используйте там url, который доступен только по http:// иначе приложение не будет работать, или используйте другой метод доступности соединения с интернетом. Также в папку приложения нужно нужно поместить еще два компонента - libeay32.dll и ssleay32.dll. Я добавил их в архив с исходником. Обновленный исходник можно взять здесь ссылка
Наконец-то получилось собрать работающий код на Indy 10, пример в архиве Докачка файлов поддерживается, прогресс выводится на Label, поддержка SSL есть, dll необходимой версии добавлены, исходник компиллировал в RAD Studio XE 5
Добавлено: сентябрь 2013
©Veterock
комментарии (1)
Создай свою клиентскую базу емайлов и номеров телефонов потенцильаных клиентов с минимальными вложениями! Продажа программы Simple audience для сбора РЕАЛЬНЫХ емайлов и номера телефонов из Facebook. Сбор можно производить по ключевым словам, а так же по списку групп. Информация на выходе: Имя, Фамилия, пол, страна, емайл, телефон. Привязка на один аккаунт - 2000р.(дальше цена будет выше). Так же предоствляем услуги по сбору любых баз - как юридических лиц так и физических! Пишите что Вам нужно- соберём не дорого! Для связи только - simpleaudience@mail.ru
добавлено: 05.07.18 12:13
Обновить
Powered by ©Veterock Studio 2013-2021