本文配套源碼
如何從Internet上有效而穩定地下載文件,這是很多網絡應用程序要考慮的重要問題,本文提供的代碼段針對這個問題進行了初步的探索。希望能夠拋磚引玉,對各位編程人員有所幫助。
UINT InternetGetFile (HINTERNET IN hOpen,
CHAR *szUrl,
CHAR *szFileName,
HWND hwndProgress,
int idStatusText,
int idProgressBar);
這裡返回值的類型為UINT,如果成功返回0,否則返回非零值。為了使用這個函數,只需要提供一個有效的HINTERNET句柄,這個句柄可以通過標准的InternetOpen()掉用來獲 得。如果你願意的話,你還可以將一個句柄提供給進度窗口(ID為一靜態控制的標示符,用來顯示狀態 ),在這個函數的頭幾行代碼中聲明一些變量。
DWORD dwSize;
這個變量被用於存儲每次 調用InternetReadFile讀取了多少數據。
CHAR szHead[] = "Accept: */*\r\n\r\n";
用於存儲多個HTTP頭信息。如果在調用InternetOpenUrl時不傳遞著個頭信 息,則只允許你打開文本文件!
VOID* szTemp[16384];
緩沖變量,可以存儲來自 Internet的16KB的文件數據。
HINTERNET hConnect;
這是一個HINTERNET句柄,包含請求結果(來自InternetOpenUrl)
FILE * pFile;
標准的C文件句柄(必須包含stdio.h)。 如果你願意,可以使用Win32處理文件的API
if (!(hConnect = InternetOpenUrlA (hOpen, szUrl, szHead, lstrlenA (szHead), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0)))
{
return INTERNET_ERROR_OPENURL;
}
此調用可以打開一個使用URL的Internet文件句柄。標 志表示這個文件總是被讀取,而不是緩存(cache)。如果失敗,則此函數返回錯誤,你可以給定 INTERNET_ERROR_OPENURL任何值。必須為這個函數定義所有的錯誤信息。也可以用一個數字替代。
if(!(pFile = fopen(szFileName, "wb" )))
{
return INTERNET_ERROR_FILEOPEN;
}
此調用根據給定的文件名打開文件。如果失敗則返回 另一個用戶定義的錯誤。
DWORD dwByteToRead = 0;
DWORD dwSizeOfRq = 4;
DWORD dwBytes = 0;
這三個值分別存儲文件的大小,HttpQueryInfo內容的大小和總共 讀取的字節數。
if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL))
{
dwByteToRead = 0;
}
此調用可以獲得文件的大小。如果失敗則dwByteToRead被 置為0,並且當文件被下載時不會顯示百分比和總數
DWORD start;
DWORD end;
DWORD time;
time = 10;
start = timeGetTime();
使用這些bit必須包含mmsystem.h並鏈接winmm.lib,它們用於時間選擇,告訴用戶下載的速度。例子代碼只統計了下載速度,你可以擴展這個功能,比如估計還剩多少時間。
do
{
if (! InternetReadFile(hConnect, szTemp, 16384, &dwSize))
{
fclose (pFile);
return INTERNET_ERROR_READFILE;
}
此調用循環中,每次下載一個16KB的數據 塊。如果download請求失敗,則文件被關閉並返回錯誤。
if (!dwSize)
break;
else
fwrite(szTemp, sizeof(char), dwSize, pFile);
如果dwSize為0,則意味著一個EOF,循環退出。否則由InternetReadFile讀取的數據內容被寫到本地文件中。
dwBytes+=dwSize;
if(dwByteToRead && hwndProgress)
{
SendDlgItemMessageA(hwndProgress, idProgressBar, WM_USER+2, (dwBytes*100)/dwByteToRead, 0);
UpdateWindow(hwndProgress);
}
這個代碼中,dwBytes是從文件讀取的數據量,它不斷增加,如果文件長度是有效的,則進度窗口句柄被指定,進度條被更新已表示下載進度 。
FLOAT fSpeed = 0;
fSpeed = (float)dwBytes;
fSpeed /= ((float) time)/1000.0f;
fSpeed /= 1024.0f;
這些bit代碼用於根據所花時間計算下載速度 和讀取的數據量。
if(hwndProgress)
{
char s[260];
sprintf(s, "%d KB / %d KB @ %1.1f KB/s", dwBytes/1024, dwByteToRead/1024, fSpeed);
SetDlgItemTextA(hwndProgress, idStatusText, s);
UpdateWindow(hwndProgress);
}
設置和處理進度窗口的狀態文本,表示下載的文件大小和下載速度。
end = timeGetTime();
time = end - start;
if(time == 0)
time = 10;
時間被更 新
} // do
while (TRUE);
循環結束
fflush (pFile);
fclose (pFile);
return 0;
}
最後,函數結束,關閉文件並清除硬件驅動的緩沖。返回0表示成功。
使用這個代碼段,按照本文所描述的那樣,你可以自己編寫一個程序來從 Internet上有效地、穩定地下載文件。實現細節請參見例子。