Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

IDHTTP некорректная докачка файла [D7, WinXP]


Cawa ©   (2006-11-23 11:30:00) 

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

Обнаружил следующее, что после обрыва связи в закаченной части файла в конце дописываются некоторое количество нулевых байтов.

Может кто поможет справиться с некорректной докачкой.


Cawa   (2006-11-23 15:57:00) [1]

2 Warstone ©
Не волнуйся, многопоточность присутствует, просто для сокращения объема выкладываемой информации (с целью её более быстрого усвоения) я нарезал и отредактировал её так, и не заметил WaitFor.
В реалии у меня существует основной поток закачки файла который создает в процессе работы два потока:
1- получающий информацию о закачивающемся файле
2- непосредственно закачивает(TDownloadFile)
и оба этих потока считывают и записывают данные в одном вспомогательном классе.
Так что я искренне извиняюсь если выкладываемые мною исходные тексты, вызвали у кого-нибудь недопонимание!!!


Warstone   (2006-11-23 14:40:00) [2]

У меня есть небольшой вопрос, а зачем в этом куске
ThreadHttp:=TDownloadFile.Create(true, Data); //Инициализация данных загрузки TotalSize, LoadSize и т.п.
 ThreadHttp.Priority:=Priority;
 ThreadHttp.Resume;
 ThreadHttp.WaitFor;
 ThreadHttp.Free; // запись результата загрузки в Data

команда

  ThreadHttp.WaitFor;

ведь смысл многопоточности пропадает. Или я чего не знаю о потоках?


Anatoly Podgoretsky   (2006-11-23 14:32:00) [3]

> Cawa  (23.11.2006 14:18:06)  [6]

Добавить строчку if LoadSize < 0 then LoadSize = 0;


Cawa   (2006-11-23 14:18:00) [4]

2 umbra ©- устанавливал значение status:=dsStop;
2 Anatoly Podgoretsky- Огромное спасибо откат помог, и как я сам не догадался?!!
2 Всех остальных- ниже привожу сделанное изменение, мало ли кому нужно осуществлять докачку


procedure TDownloadFile.Execute;
var
FileStream : TFileStream;
begin
HTTP := TIdHTTP.Create(nil);
LoadSize:=Loadsize-HTTP.RecvBufferSize; // исправление здесь :))
if FileExists(Directory + '\' + FileName) then


umbra   (2006-11-23 14:12:00) [5]

в принципе можно запрашивать файл по кускам в промежуточный поток, а в скачанный файл дописывать только когда получен блок нужного размера. Наподобие


const
  ChunkSize = 4096;


procedure TDownloadFile.Execute;
var
FileStream : TFileStream;
TmpStream: TMemoryStream;
begin
HTTP := TIdHTTP.Create(nil);
if FileExists(Directory + '\' + FileName) then
begin
  FileStream := TFileStream.Create(Directory + '\' + FileName, fmOpenReadWrite);
  //FileStream.Position := FileStream.Size;
  FileStream.Position:=LoadSize;
end else
begin
  FileStream := TFileStream.Create(Directory + '\' + FileName, fmCreate);
end;
TmpStream := TMemoryStream.Create;

while FileStream.Size < TotalSize do
begin
 TmpStream.Position := 0;
 HTTP.Request.ContentRangeStart := FileStream.Size;
 if TotalSize - FileStream.Size >= ChunkSize then
   HTTP.Request.ContentRangeEnd := FileStream.Size + ChunkSize
 else
   HTTP.Request.ContentRangeEnd := TotalSize;
 try
   HTTP.Get(URL, TmpStream);
 except
   on E : Exception do
     begin
       TmpStream.SetSize(0);
       {.........................................}
     end;
end;
if TmpStream.Size > 0 then
   FileStream.CopyFrom(TmpStream, 0);

end;

HTTP.Free;
tmpstream.Free;
FileStream.Free;

End;


Anatoly Podgoretsky   (2006-11-23 12:32:00) [6]

> Cawa  (23.11.2006 11:32:01)  [1]

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


umbra   (2006-11-23 12:14:00) [7]

а останавливаете закачку как?


Cawa   (2006-11-23 11:32:00) [8]

Вот часть кода модуля по закачке

TDownloadStatus = (dsReady, dsError, dsLoad, dsLoading, dsStoped, dsDelete, dsDeleted);

TDownloadFile = class(TThread)
 public
   URL: String;
   FileName: String;
   Directory: String;
   TotalSize: Integer;
   LoadSize: Integer;
   Status: TDownloadStatus;
   ErrorText: String;
 … … …
 private
   StartSize : Integer;
   HTTP      : TIdHTTP;
   procedure OnWork(Sender : TObject; AWorkMode : TWorkMode; const AWorkCount : Integer);
   procedure OnWorkBegin(Sender : TObject; AWorkMode : TWorkMode; const AWorkCountMax : Integer);
   procedure OnWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
 protected
   procedure Execute; override;
end;

////////////////////////////////////////////////////////////////////////////////

procedure TDownloadFile.Execute;
var
 FileStream : TFileStream;
begin
 HTTP := TIdHTTP.Create(nil);
 if FileExists(Directory + '\' + FileName) then
 begin
   FileStream := TFileStream.Create(Directory + '\' + FileName, fmOpenReadWrite);
   //FileStream.Position := FileStream.Size;
   FileStream.Position:=LoadSize;
 end else
 begin
   FileStream := TFileStream.Create(Directory + '\' + FileName, fmCreate);
 end;
 HTTP.OnWork := OnWork;
 HTTP.OnWorkBegin := OnWorkBegin;
 HTTP.OnWorkEnd := OnWorkEnd;
 HTTP.Request.ContentRangeStart :=LoadSize;
 HTTP.Request.ContentRangeEnd := TotalSize;

… // настройки соединения proxy redirect и т.д. …

 StartSize := LoadSize;
 try
   HTTP.Get(URL, FileStream);
 except
   on E : Exception do
   begin
     Status := dsError;
     ErrorText := E.Message;
     MessageBox(Application.Handle, PChar('Ошибка при загрузке файла.' + #13#10 + E.Message), PChar(Options.Name), MB_OK or MB_ICONERROR);
   end;
 end;

 HTTP.Free;
 FileStream.Free;

End;

////////////////////////////////////////////////////////////////////////////////

procedure TDownloadFile.OnWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
begin
 if AWorkMode = wmRead then
 begin
   LoadSize := StartSize + AWorkCount;
 end;
 if Status = dsStoped then HTTP.Disconnect;
end;

////////////////////////////////////////////////////////////////////////////////

procedure TDownloadFile.OnWorkBegin(Sender : TObject; AWorkMode : TWorkMode; const AWorkCountMax : Integer);
begin
 Status := dsLoading; // начало загрузки
end;


Cawa   (2006-11-23 11:32:00) [9]

часть кода по инициализации закачки (он же и по докачке)

var
 HTTP : TIdHTTP;
 ThreadHttp:TDownloadFile;
begin
 HTTP := TIdHTTP.Create(nil);
 try
   HTTP.Head(Data.URL);
   Data.Status:= dsReady;
   Data.ErrorText := 'Ошибок нет';
   Data.TotalSize := HTTP.Response.ContentLength;
 except
   on E : Exception do
   begin
     Data.Status := dsError;
     Data.ErrorText := E.Message;
     Data.TotalSize := 0;
     MessageBox(Application.Handle, PChar('Ошибка при загрузке файла.' + #13#10 + E.Message), PChar(Options.Name), MB_OK or MB_ICONERROR);
   end;
 end;
 HTTP.Free;
If Data.Status<>dsError then
begin
  ThreadHttp:=TDownloadFile.Create(true, Data); //Инициализация данных загрузки TotalSize, LoadSize и т.п.
  ThreadHttp.Priority:=Priority;
  ThreadHttp.Resume;
  ThreadHttp.WaitFor;
  ThreadHttp.Free; // запись результата загрузки в Data
End;


Наверх

Титульная страница Поиск, карта сайта Написать письмо