Ściąganie pliku z internetu
murdoc
Nie myślałem że to bedzie takie popularne ale skoro.....
Program służy do ściągania plików lub stron internetowych.
Część rzeczy można stąd pominąć a część należałoby zmienić na własny użytek, ale to by pogorszyło czytelność.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
wininet,
StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
Button1: TButton;
Button2: TButton;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
stop: boolean;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
hInet,
hURL: HINTERNET;
fSize,
ReadLen,
RestartPos: DWORD;
fBuf: array[1..1024] of byte;
f: file;
Header: string;
begin
RestartPos := 0;
fSize := 0;
Button1.Enabled := false;
Button2.Enabled := true;
if FileExists('c:\123.tmp') then {tu należy podać nazwę pliku ściąganego-->>a więc funkcja odpowiednia :)}
begin
AssignFile(f, 'c:\123.tmp');
Reset(f, 1);
RestartPos := FileSize(F); {gdy plik już istnieje na naszym komputerze to ustawiamy pointer na końcu pliku żeby potem zacząć kopiowanie pliku od miejsca w którym skończyliśmy}
Seek(F, FileSize(F));
end
else
begin
AssignFile(f, 'c:\123.tmp'); {jeśli zaczynamy kopiować plik po raz pierwszy to ustawiamy się na początku pliku}
ReWrite(f, 1);
end;
hInet := InternetOpen('Mozilla', {ble,ble->>patrz na samym dole}
PRE_CONFIG_INTERNET_ACCESS,
nil,
nil,
0);
Header := 'Accept: */*';
hURL := InternetOpenURL(hInet,
PChar(Edit1.Text),
pchar(Header),
StrLen(pchar(Header)),
0,
0);
if RestartPos > 0 then {jeśli chcemy dokończyć kopiowanie pliku to wtedy ustaw pointer w pliku internetowym na miejscu w którym skończyliśmy ostatnio}
InternetSetFilePointer(hURL,
RestartPos,
nil,
0,
0);
InternetQueryDataAvailable(hURL, fSize, 0, 0);
if RestartPos > 0 then
begin
ProgressBar1.Min := 0;
ProgressBar1.Max := fSize + RestartPos;
ProgressBar1.Position := RestartPos;
end
else
begin
ProgressBar1.Min := 0;
ProgressBar1.Max := fSize + RestartPos;
end;
while (ReadLen <> 0) and (stop = false) do
begin
InternetReadFile(hURL, @fBuf, SizeOf(fBuf), ReadLen);
InternetQueryDataAvailable(hURL, fSize, 0, 0);
ProgressBar1.Position := ProgressBar1.Max - fSize;
BlockWrite(f, fBuf, ReadLen);
Application.ProcessMessages;
end;
stop := false;
Button1.Enabled := true;
Button2.Enabled := false;
InternetCloseHandle(hURL); {zwalnianie poszczególnych uchwytów}
InternetCloseHandle(hInet);
CloseFile(f); //zamknięcie pliku
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
stop := false;
Button2.Enabled := false;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
stop := true;
end;
end.
HINTERNET-uchwyt potrzebny podczas pracy z protokołem http;
fSize, ReadLen, RestartPos: DWORD-odpowiednio:wielkosc pliku,pozycja w pliku,pozycha w pliku gdy chcemy dokonczyć ściąganie pliku;
fBuf: array[1..1024] of byte-tablica bufora do której kopiujemy dane;
Teraz opiszę dokładnie składnię internetopen(żeby każdy mógł se dostosować program ) która zwraca uchwyt i który wskazuje na wykorzystanie w aplikacji Wininet :
hinet:=
nazwa_aplikacji- może to być dowolna wartość typu string;
rodzaj_żądanego_dostępu-(np. INTERNET_OPEN_TYPE_DIRECT,INTERNET_OPEN_TYPE_PRECONFIG,INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY,INTERNET_OPEN_TYPE_PROXY),
nazwa_servera_proxy_jesli_uzywa_sie_proxy-(w tym przypadku nie używamy servera proxy więć wartość ta wynosi nil(patrz "rodzaj żądanego dostępu)),
nazwy_hostów -gdy używamy połączeń proxy które nie powinny być rutowane( w naszym przypadku nie używamy proxy więc w tym miejscu wpisujemy nil),
opcjonalne_flagi- (INTERNET_FLAG_ASYNC,INTERNET_FLAG_FROM_CACHE,INTERNET_FLAG_OFFLINE) w naszym przypadku bez flag więc 0;
Składnia internetopenurl (uchwyt do zasobów) :
hurl:=
hinet=uchwyt otrzymany wcześniej (wskazujacy na obecnie otwartą sesję),
adres_internetowy_pliku-nic dodac nic ujać :),
nagłówek_wysyłany_do_servera_http,
długość_nagłówka,
flagi
context- wskazuje na określoną przez aplikację wartość która jest wysyłana w przypadku odpowiedzi ( w tym przypadku 0)
InternetQueryDataAvailable określa wielkość dostępnych danych.
InternetSetFilePointer( uchwyt_do_pliku,pozycja_w_pliku_od_której_zaczynamy_czytać_dane,
zarezerwowane(musi być nil),początkowe_miejsce_od_którego_wystąpi_przesunięcie(FILE_BEGIN,FILE_current lub File_end),
context(zarezerwowane)_i_musi_wynosić_0-ustawia pozycję w pliku który chcemy skopiować,
Kopiowania plików nie będę tłumaczył (f1)
Jeżeli ktoś potrzebuje więcej opisów to radzę do internetu zajrzeć bo ja już więcej pisania nie zdzierżę.
P.S. Jak sa błedy to nie moja wina bo śpiący jestem
Bo kurde program jest zle napisany ;-))))
Do wyznaczania wielkosci pliku uzyta zostala funkcja InternetQueryDataAvailable, ktora do tego nie sluzy. Zwraca ona cytujac MSDN "the amount of data available", czyli przyznany przez serwer kawalek pliku do jednorazowego odczytu. W zamian powinna byc zastosowana HttpQueryInfo. Oczywiscie funkcja dziala tylko dla plikow i stron statycznych. Jadro programu powinno wgladac mniej wiecej tak jak ponizej.
(sorki za C++, ale chcialem, uniknac mozliwych do popelnienia bledow przy tlumaczeniu na "pale", mam nadzieje ze koledzy sobie poradza ;-) )
Pozdrawiam Centy.
PS
Use MSDN Luke... ;-)
bool ReadFromInternet (AnsiString URL, AnsiString OutputFile, TProgressBar *progressBar)
{
}
Tematyka podobna, tylko inna metoda: http://4programmers.net/faq.php?id=8
Kurde wie ktoś dlaczego przy ściąganie pasek statusu wariuje?
hehe.. ten kodzik z malymi zmiankami .. tzn wywaleniem tego RestartPos to smiga jak pojeb..... swietny kod. Dziemki :D !!
Mam pytanko do nagłówka (Header :) ).
Jeśli chciałbym w nim podać więcej paramertów to w jaki sposób? Oddzelać je średnikami/przecinkami/etc.
W jakiej formie je przekazywać nazwa:wartość/ nazwa=wartość
Grzebałem troszke w necie ale za dużo nie znalazłem. Podrzyć może jakieś konkretne, wartościowe linki.
zmienna <B>fSize</B> nie zawiera wielkości pliku. zazwyczaj jest to 0 albo kilka bajtów. Pliki które próbowałem nie są stronami php czy coś w tym stylu. próbowałem na wielu różnych plikach i stronach. Zawsze było to żle podawane. Gdzie szukać błędu?
Mam pytanko. Dlaczego jak zatrzymuję ściąganie pliku i wznawiam ponownie to program nie chce dokończyć owego ściągnięcia?
Komentarz Grześkowi::
Nie chciałem nikomu o tym mówić Grzesiek (tzn. o zerźnięciu kodu) ale skoro jestem zmuszony to zdradzę tajemnicę.....a więc było tak ::
Pewnego dnia gdy siedziałem na kiblu przeżywając wypróżnienie stulecia, w momencie kulminacyjnym przyszły do mnie krasnoludki i powiedziały tak: "Masz tu kod jak zastosować Winapi w Delphi, nikt tego kodu nie zna oprócz ciebie i nikt nie wie jak go używać jeszcze. Niech moc będzie z tobą".
W taki oto sposób stałem się posiadaczem tego tajemniczego, nikomu nie znanemu kodu.
Poprawiłem co mogłem i starałem się wszystko okroić żeby było jak najbardziej czytelne.
P.S. Czasem progressbar przy większych plikach źle pokazuje mi pozycję....nie wiem czemu na razie.
Możemy liczyć na opis czy ten kod zerżnąłeś i sam nie wiesz, o co w tym kodzie chodzi!?
artykulik całkiem niezły... i przydatny przdewszystkim :)
wlasnie przydaly by sie jakies opiski, komentarze ;p ale to zalezy od autora
A jak się wyśpisz to dodasz jakiś komentarz?
Tytuł jest świetny - mówi wszystko [rotfl] ;)
< delphi > </ delphi>