Конференция "Начинающим" » Докачка файлов через idhttp. [D7, WinXP]
 
  • vegarulez (23.05.10 22:45) [0]
    Привет всем мастерам!
    Возникла задача скачивания файлов из интернета.
    Скачал довольно хороший пример.

    delphi.int.ru/download/file/257/


    но там нет такого нужного момента как докачка файла, при разрыве соединения.
    Полазил в интернете и нашёл ещё пример

    delphisources.ru/pages/sources/internet/2005_year/download_plus.html



    но он не компилиться под d7+indy10.1.5
    Прошу помочь с этим вопросом.

    Почитал статьи в интернете, и скачал пару примеров с использованием WinInet.

    delphisources.ru/pages/faq/base/download_with_download_again.html


    Там используется такой параметр как range, используя его в заголовке idhhtp можно организовать докачку, но тут вопрос метод get при обращении на скачивание файла скидывает в поток поток пишет в файл. Тут просто у меня не понимание - как продолжить дописывать файл при разрыве соединения и организации повторного закачивания?
  • vegarulez (23.05.10 22:55) [1]
    для первого примера - описание delphi.int.ru/articles/39/

    Второй пример не компилиться в юните uThreads ругается на  строку
    HTTP.OnWork := OnWork;


    ошибку выводит:
    incompatible types: 'Parameters lists differ'
    Посомтрел в первом примере - там впринципе также работа с onwork происходит... подскажите что может быть не так???
  • Медвежонок Пятачок © (23.05.10 23:20) [2]
    скзано же по-русски:
    incompatible types: 'Parameters lists differ'

    текущая версия инди имеет другой список параметров обработчика OnWork по сравнению с компилируемым примером.
  • vegarulez (23.05.10 23:23) [3]
    Список тот же, которые в процедуре обработчика... что в первом примере что во втором
  • vegarulez (23.05.10 23:25) [4]
    хотя не... разница увидена
    Sender : TObject;
    и
    ASender : TObject;
  • vegarulez (23.05.10 23:28) [5]
    Хотя не... всё там также (
  • vegarulez (23.05.10 23:42) [6]
    Нашёл. Поменял. 2-ой пример запустился.
  • vegarulez (24.05.10 00:19) [7]
    только докачка в том понимании в каком она должна быть - не пашет (
  • Медвежонок Пятачок © (24.05.10 00:19) [8]
    Список тот же, которые в процедуре обработчика.

    Если бы он был тот же, то не было бы
    incompatible types: 'Parameters lists differ'
  • Плохиш © (24.05.10 10:41) [9]

    > Там используется такой параметр как range, используя его
    > в заголовке idhhtp можно организовать докачку, но тут вопрос
    > метод get при обращении на скачивание файла скидывает в
    > поток поток пишет в файл. Тут просто у меня не понимание
    > - как продолжить дописывать файл при разрыве соединения
    > и организации повторного закачивания?

    Поток, в который скидывают, никуда сам ничего не пишет. Т.ч. надо просто написать часть программы, которая записывает полученные данные в файл на нужное место.
  • vegarulez (26.05.10 12:24) [10]
    TFileStream.Create(ToFolder, fmCreate);

    А файл уже есть, допустим часть скачена уже. Не знаю как правильно сделать чтобы поток TFileStream приклеил к уже существующему файлу следющую часть...

    думаю сделать так - проверять есть ли файл, если нет - то запрашивать его размер и качать по частям через range, далее эти части "склеивать" между собой. Ну сообствено зная стандартный размер части будет понятно скачалась она полностью или нет, взависимости от этого переходить к скачиванию следующей части.
  • Palladin © (26.05.10 12:31) [11]
  • Плохиш © (26.05.10 12:34) [12]
    1. Запроси размер файла
    2. Создай filestream требуемого размера
    3. пиши каждую принятую часть в соответствующее место стрима.

    PS. из [9] "надо просто написать часть программы, которая записывает полученные данные в файл на нужное место."
  • vegarulez (27.05.10 17:19) [13]
    пока что пытаюсь сделать без потока, просто пробую... натыкаюсь на ряд не понятных моментов.

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

    Подскажите, где что не так...

    Думаю может в
    IdHTTP1.OnWork передвигать указатель tfilestream, но это как то муторно... подскажите плиз.

    procedure TForm1.Button3Click(Sender: TObject);
    var
    IdHTTP1:TidHttp;
    SourceFileSize: Dword;
    FileDate: TDateTime;
    SourceFile, SourceURL,FileType: string;
    fDownloadStream: TFileStream;
    begin
    SourceFile:=Edit2.Text;
    SourceURL := Edit1.Text;
    IdHTTP1:=TIdHTTP.Create(nil);
    IdHTTP1.ProtocolVersion := pv1_1;
    IdHTTP1.HandleRedirects := True;
    IdHTTP1.Head(SourceURL);
    SourceFile := IdHTTP1.URL.Document;
    SourceFileSize := IdHTTP1.Response.ContentLength;
    FileDate := IdHTTP1.Response.LastModified;
    FileType := IdHTTP1.Response.ContentType;
    if FileExists(IdHTTP1.URL.Document) then
    begin
    fDownloadStream := TFileStream.Create(SourceFile, fmOpenReadWrite);
    Idhttp1.Request.Range:=Format('%d-%d',[fDownloadStream.Position,
    SourceFileSize-1]);
    fDownloadStream.Seek(SourceFileSize,soFromBeginning);
    end
    else
    begin
    fDownloadStream := TFileStream.Create(SourceFile, fmCreate);
    fDownloadStream.Seek(0,soFromBeginning); //
    end;
    IdHTTP1.Request.ContentType := FileType;
    IdHTTP1.Request.ContentRangeStart := fDownloadStream.Position;
    IdHTTP1.Request.ContentRangeEnd := SourceFileSize;
    IdHTTP1.Get(SourceURL,fDownloadStream);
    fDownloadStream.Free;
    IdHTTP1.Free;
    end;

  • vegarulez (27.05.10 17:19) [14]
    пока разбираюсь пробую без потоков (Tthread).
  • Медвежонок Пятачок © (27.05.10 17:28) [15]
    но смотрю он увеличивает размер файла ровно в 2 раза.

    один и тот же файл скачан 2 раза.
    все принятые байты записаны в один и тот же локальный файл.
  • vegarulez (27.05.10 21:07) [16]
    Да я понимаю. но почему он не перемещает указатель потока при помещении в файл. постпенно. а сразу выделет место на диске под весь файл? т.е. грубо говоря, файл не меняетет свой размер он сразу создаётся того размера, который должен быть уже после полного скачивания, но по сути вещей он только начинает его качать.
    при каждом повторном запуске он опять приклеивает к файлу его размер, и так какждый раз при каждом следующем запуске, хотя реально скачивание только началось...
    указатель на размер файла вроде почитав про это перемещаю в начало... и при повторном скачивании тоже смотрю сколько скачал, чтоб поставить указатель...
    fDownloadStream.Seek(SourceFileSize,soFromBeginning);

    но почему то этого не происходит (

    подскажите как быть ...
  • Медвежонок Пятачок © (27.05.10 22:30) [17]
    кто "он"?

    и почему "он" должен что-то перемещать?
    перемещать должен программист.

    при каждом повторном запуске он опять приклеивает к файлу его размер

    Все в полном соответствии как ты и просил.
    Локальный файл открыт, указатель смещен в конец.
    Далее с сервера еще раз запрошен скачиваемый файл.
    Он благополучно скачивается как и просилось тобой.
    Все скачанные байты записываются в стрим с текущей позиции указателя.

    Все как ты и просил (точнее как ты и запрограммировал).

    подскажите как быть ...

    и быть или не быть вообще.
  • Anatoly Podgoretsky © (28.05.10 07:16) [18]
    > vegarulez  (27.05.2010 21:07:16)  [16]

    Это ошибка генофонда, он должен был не увеличивать его, а ставить равным или
    вообще наращивать по мере необходимости. Пиши своего наследника с
    исправленым функционалом или переходи на другие компоненты.
  • vegarulez (28.05.10 08:15) [19]
    Медвежонок Пятачок ©   (27.05.10 22:30) [17]
    Anatoly Podgoretsky ©   (28.05.10 07:16) [18]
    премного благодарен за развёрнутые ответы, и описание личности...
    а по существу вопроса?

    Указатель перемещён, всё замечательно - но файл то только начинает скачиваться и я его тут же обрубаю - т.е. грубо говоря скачалось 200 кбайт а на диске уже создан файл в 10 мб. Я вот это не могу понять. Почему создаётся сразу файл размером со скачиваемый файл, когда скачалось всего 200 кб?

    Локальный файл открыт, указатель смещен в конец.

    ну как же так? я же его помещаю в начало:
    fDownloadStream := TFileStream.Create(SourceFile, fmCreate);
    fDownloadStream.Seek(0,soFromBeginning);



    Понимаю, что что-то не до понимаю. Прошу без сарказма указать путь истинный :)
  • Anatoly Podgoretsky © (28.05.10 09:00) [20]
    > vegarulez  (28.05.2010 08:15:19)  [19]

    Тебе по существу несколько раз объяснили, и не наша проблема, что ты этого
    не понимаешь.
  • Anatoly Podgoretsky © (28.05.10 09:01) [21]
    > vegarulez  (28.05.2010 08:15:19)  [19]

    Кстати ты что принял на свой счет, насчет своей личности, случайно не слово
    ли Генофонд?
  • vegarulez (06.06.10 09:34) [22]
    Anatoly Podgoretsky ©   (28.05.10 09:01) [21]
    ну да... были сомнения...

    Ну всё. Всё получилось. Докачку сделал. определили размер файла и сделал через поток и параметр Request.Range - всё рабит на ура.

    Теперь вопрос в следующем. Как можно реализовать crc проверку файла?
    ну т.е. [не знаю как правильно выразиться] допустим есть у меня файл 1.rar, потом появился на его месте новый файл, c тем же названием 1.rar а он допустим не докачался до конца в предыдущий раз, я запускаю программу и она соответсвенно начнёт качать с того байта где была остановлена, но файл то уже совсем другой. Я планирую сделать проверку на размер файла + дата изменения которые получаю перед закачкой.

    FileDate := IdHTTP1.Response.LastModified;
    FileType := IdHTTP1.Response.ContentType;



    Поэтому вопрос есть ли более элегантный способ, допустим всзять md5 хэш или crc... подскажите как правильно сделать верификацию...
  • Anatoly Podgoretsky © (06.06.10 09:42) [23]
    > vegarulez  (06.06.2010 09:34:22)  [22]

    Да какая разница, тот или другой файл, все равно качать с последней позиции,
    а еще лучше с последней позиции минус 1 килобайт. Кроме того, как ты
    посчитаешь CRC не закачав весь файл?. Но проверять все равно надо, но по
    известному CRC для проверки целостности файла.
    Контроль можно сделать и по другому, сначала скачивать рядом лежащий CRC и
    сравнивать с сохраненым. В качестве CRC принять использовать MD5. Можно
    также поступать по принципу торрент файлов, когда CRC не один, а множество,
    по одному CRC на каждый блок фиксированого размера, скажем на каждые 4 кб
    или более.
  • vegarulez (06.06.10 23:50) [24]
    Заметил, что передаётся параметр ETag, в котором скорее всего содержится crc. Вопрос как оно закодировано? md5?
  • vegarulez (07.06.10 00:03) [25]
    Хотя странно - если бы это был md5 хэш зачем его тогда разделять через чёрточку... подскажите...

    Date: Sun, 06 Jun 2010 20:01:53 GMT
    Server: Apache/2.2.3 (Red Hat)
    Last-Modified: Sat, 22 May 2010 09:10:10 GMT
    ETag: "293200b-ae3fb0-4872b2cb14080"
    Accept-Ranges: bytes
    Content-Length: 11419568
    Connection: close
    Content-Type: text/plain

  • vegarulez (07.06.10 00:35) [26]
    Так... ну вроде понимание про Etag пришло.

    ETag  (Entity tag) является уникальным идентификатором версии объекта и чаще всего генерируется какой-либо  хэш-функцией . Спецификация не навязывает каких-либо алгоритмов для  вычисления  значения  ETag  — главное чтобы это значение было уникально для всех различных версий одного объекта. Значение ETag одного объекта может совпадать со значением другого, из этого не следует эквивалентность этих объектов.



    т.е. таким образом не имеет смысла вычисления md5 файла, уже скаченного. проще разруливать, при запросе, по хэшу ETag?

    В верном направлении мысль пошла?
  • vegarulez (07.06.10 06:43) [27]
    Anatoly Podgoretsky ©   (06.06.10 09:42) [23]
    почему лучше минус 1 кб???
  • vegarulez (15.06.10 07:23) [28]
    vegarulez   (07.06.10 00:35) [26]

    В верном направлении мысль пошла????

    vegarulez   (07.06.10 06:43) [27]
    почему лучше минус 1 кб???
  • имя (09.08.10 20:50) [29]
    Удалено модератором
  • имя (11.08.10 01:05) [30]
    Удалено модератором
  • имя (11.08.10 01:09) [31]
    Удалено модератором
  • tebeen (04.10.10 04:54) [32]
    fDownloadStream := TFileStream.Create(SourceFile, fmCreate);
    fDownloadStream.Seek(0,soFromBeginning); //


    вот где собака зарыта.

       msUpData:=TMemoryStream.Create;
           http.Get('http://....ru', msUpData);


    лучше так.
 
Конференция "Начинающим" » Докачка файлов через idhttp. [D7, WinXP]
Есть новые Нет новых   [134437   +29][b:0][p:0.002]