Jednoduché riešenie pre vaše programy, ktoré potrebujú sťahovať súbory z Internetu. Ak ste uvažovali o rozšírení svojej aplikácie alebo minimálne vašich vedomostí o možnosť sťahovať dáta z Internetu pomocou C++, tak po prečítaní tohto článku by vám to nemalo robiť problém.
K dosiahnutiu tohto cieľa existuje viacero ciest, no pre programátorov v prostredí Windows je najefektívnejšie využiť WinInet. Dôvody, prečo je tomu tak, v krátkosti objasním.
K súborom, ktoré sa nachádzajú v sieti Internet, sa najčastejšie pristupuje pomocou protokolu HTTP. HTTP teda slúži na výmenu dát medzi klientom a serverom. Nachádza sa na 4. (aplikačnej) vrstve TCP/IP modelu. Pod ním sa nachádza vrstva transportná, sieťová a fyzická. HTTP je závislé na TCP (Transmission Control Protocol), ktoré je svojim protokolom náročné na aplikovanie. WinInet sa však stará o tieto problémy za nás, a nám sa tak ponúka komfortné implementovanie HTTP služieb.
Samotný postup sťahovania dát z Internetu pomocou WinInet sa skladá z niekoľkých krokov. Prvým z nich je nadviazanie spojenia, resp. vytvorenie inštancie, ktorá sa použije pri otváraní internetových súborov, alebo ešte inak povedané, inicializovanie WinInet pre použitie v aplikácii. Druhým krokom je otvorenie internetového súboru a tretím samotné prečítanie tohto súboru. Tieto tri základné kroky sú však v tomto článku rozšírené, aby sme si ukázali postupy, ktoré je vhodné dodržať. Napríklad zistenie statusu práve otvoreného internetového súboru nie je nutné, no môže nám povedať, či sa daný súbor otvoril, zistiť jeho veľkosť a iné, i keď menej dôležité informácie.
Začal by som popisom jednotlivých funkcií, ktoré v tomto programe použijeme. WinInet obsahuje množstvo užitočných funkcií, no rád by som vám poskytol len základy, na ktorých sa môžete realizovať a rozvíjať. Pre viac informácií môžete navštíviť referencie na MSDN.
-
Prvou takou funkciou, ktorú v našom programe použijeme je:
DWORD InternetAttemptConnect(DWORD rezervovane);
-
HINTERNET InternetOpen(LPCTSTR agent,DWORD typPristupu,LPCTSTR nazovProxy,LPCTSTR proxyBypass,DWORD priznaky);
-
HINTERNET InternetOpenUrl(HINTERNET hInternet,LPCTSTR url,LPCTSTR hlavicky,DWORD dlzkaHlaviciek,DWORD priznaky,DWORD_PTR kontext);
-
BOOL InternetReadFile(HINTERNET internetovySubor,LPVOID zasobnik,DWORD pocetBajtovNaPrecitanie,LPDWORD pocetPrecitanychBajtov);
-
BOOL HttpQueryInfo(HINTERNET request,DWORD typInformacie,LPVOID zasobnik,LPDWORD velkostZasobnika,LPDWORD index);
//---------------------------------------------------------------------------------
// Sťahovanie súborov z internetu pomocou WinInet
//---------------------------------------------------------------------------------
#include
#include
#include
#include
#include // hlavičkový súbor knižnice WinInet
//---------------------------------------------------------------------------------
#define VELKOST_VYROVNAVACEJ_PAMATE 256 // veľkosť vyrovnávacej pamäte použitej
// pri čítaní internetového súboru
//---------------------------------------------------------------------------------
#pragma comment(lib,"WinInet.lib") // prilinkovanie knižnice WinInet
//---------------------------------------------------------------------------------
using namespace std;
//---------------------------------------------------------------------------------
int main(int argc, char * argv[])
{
cout << "Stahovanie suborov z internetu" << endl;
string url,subor;
cout << "Zadajte URL suboru: ";
getline(cin,url);
cout << "Zadajte nazov suboru na ulozenie: ";
getline(cin,subor);
// V prvom rade si deklarujeme premenné, ktoré budeme používať
HINTERNET spojenie,internetovySubor;
// Ďalej sa pokúsime o spojenie
if (InternetAttemptConnect(0) != ERROR_SUCCESS)
{
// Spojenie nie je možné nadviazať, resp. nie je možné pracovať v online móde
cout << "Nebolo mozne sa pokusit o spojenie" << endl;
cout << "Kod chyby: " << GetLastError() << endl;
return 1;
}
// Teraz si vytvoríme spojenie, inicializujeme aplikáciu na používanie WinInet
spojenie = InternetOpenA("Moj internetovy prehladavac",
INTERNET_OPEN_TYPE_PRECONFIG, // Predvolené nastavenia
0, // Žiadne proxy
0,
0); // Žiadne príznaky
if (spojenie == 0) // NULL
{
cout << "Nie je mozne inicializovaz WinInet" << endl;
cout << "Kod chyby: " << GetLastError() << endl;
return 1;
}
// Následne otvoríme spojenie so súborom, ktorý je definovaný pomocou URL
internetovySubor = InternetOpenUrlA(spojenie, // Inštancia spojenia
url.c_str(), // URL adresa súboru
0, // Žiadna prídavná HTTP hlavička
0, // Dĺžka prídavnej hlavičky
0, // Žiadne príznaky
0);
if (internetovySubor == 0) // NULL
{
cout << "Nie je mozne vytvorit spojenie so suborom" << endl;
DWORD kodChyby = GetLastError();
cout << "Kod chyby: " << kodChyby << endl;
char chyba[256];
DWORD chybaVelkost = 255;
if (InternetGetLastResponseInfoA(&kodChyby,chyba,&chybaVelkost))
cout << "Popis chyby: " << chyba << endl;
// Nesmieme zabudnúť zatvoriť už inicializovaný handler s WinInet
InternetCloseHandle(spojenie);
return 1;
}
// V tomto kroku môžeme zistiť podrobnosti o súbore
DWORD informacia;
DWORD velkostInformacie = sizeof(DWORD);
// Najskôr si zistíme HTTP status kód (napr. status kód 200 znamená OK, 404 znamená súbor nenájdený)
if (!HttpQueryInfoA(internetovySubor, // Inštancia nami vytvoreného spojenia so súborom
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, // Požadujeme status ktorý je číselným typom
&informacia, // Sem bude zapísaný výsledok volania
&velkostInformacie, // Veľkosť dátovej jednotky informácie
0))
{
cout << "Nie je mozne zistit kod statusu" << endl;
cout << "Kod chyby: " << GetLastError() << endl;
InternetCloseHandle(internetovySubor);
InternetCloseHandle(spojenie);
return 1;
}
cout << "Status odpovede: " << informacia << endl;
// Ak sa status odpovede nerovná 200, nedostaneme súbor, ktorý sme požadovali
if (informacia != HTTP_STATUS_OK)
{
cout << "Status spojenia NIE je OK" << endl;
InternetCloseHandle(internetovySubor);
InternetCloseHandle(spojenie);
return 1;
}
// Teraz si zistíme veľkosť súboru
if (!HttpQueryInfoA(internetovySubor, // Inštancia nami vytvoreného spojenia so súborom
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, // Požadujeme status ktorý je číselným typom
&informacia, // Sem bude zapísaný výsledok volania
&velkostInformacie, // Veľkosť dátovej jednotky informácie
0))
{
// Síce sme nezistili veľkosť súboru, ale to nám neprekáža v jeho stiahnutí
cout << "Velkost suboru sa neda zistit" << endl;
informacia = 0;
}
// Vytvoríme si vyrovnávaciu pamäť, do ktorej budeme ukladať časti súboru
char * vyrovnavaciaPamat = new char[VELKOST_VYROVNAVACEJ_PAMATE];
// Vytvoríme si výstupný súbor
fstream vystupnySubor(subor.c_str(), // Názov výstupného súboru
ios_base::out | ios_base::binary); // Budeme zapisovať v binárnom móde
// Premenná, do ktorej sa bude ukladať koľko sme z internetového súboru prečítali
DWORD precitane = 0;
// Premenná, do ktorej uložíme celkový počet stiahnutých bajtov
DWORD stiahnute = 0;
cout << "Stahujem\t\t\t";
while (InternetReadFile(internetovySubor, // Spojenie na náš internetový súbor
vyrovnavaciaPamat, // Vyrovnávacia pamäť
VELKOST_VYROVNAVACEJ_PAMATE, // Koľko môžeme max. prečítať
&precitane)) // Koľko WinInet prečítal
{
if (precitane == 0) // Už sme všetko prečítali, ukončiť
break;
stiahnute += precitane;
if (informacia != 0) // Ak vieme o veľkosti súboru môžeme vypočítať %
cout << "\rStahujem " << (int)((stiahnute*100)/informacia) << "%";
else // Inak len vypíšeme celkový počet stiahnutých B
cout << "\rStahujem " << stiahnute << " B";
// Zapísať do vsýtupného súboru
vystupnySubor.write((const char*)vyrovnavaciaPamat,precitane);
}
cout << endl << endl;
// Zistíme chybu (ak nejaká nastala)
DWORD chyba = GetLastError();
if (chyba != 0)
{
cout << "Pri citani vznikla chyba" << endl;
cout << "Kod chyby: " << chyba << endl;
char chybaText[256];
DWORD chybaVelkost = 255;
if (InternetGetLastResponseInfoA(&chyba,chybaText,&chybaVelkost))
cout << "Popis chyby: " << chyba << endl;
}
else
{
cout << "Hotovo" << endl;
}
// Zatvoríme spojenia
InternetCloseHandle(internetovySubor);
InternetCloseHandle(spojenie);
// Zatvoríme výstupný súbor
vystupnySubor.close();
// Nezabudneme vyrovnávaciu pamäť uvoľniť :)
delete [] vyrovnavaciaPamat;
return 0;
}
Už funkčný exe súbor spolu s kódom nájdete na: http://router.xf.cz/cppfiledownload.zip