如何从Internet上有效而稳定地下载文件

First, create a function to handle downloading of a file from the web. My example is like this:

UINT InternetGetFile (HINTERNET IN hOpen, CHAR *szUrl, CHAR *szFileName, HWND hwndProgress, int idStatusText, int idProgressBar);

It's UINT because it will return a value if an error occurs. Otherwise, it will return 0. In order to use this function, all you have to do is provide a valid HINTERNET handle obtained using a standard InternetOpen() call. If you want, you can provide a handle to a progress window (and an ID for the STATIC control for status, and the PROGRESS control for the progress bar), where the function will display its status. Everything else is self-explanatory. I begin the body of the function declaring some variables.

DWORD dwSize;

 

This variable will be used to store how much data is read with every call to InternetReadFile.

CHAR szHead[] = "Accept: */*\r\n\r\n";

 

In this variable, the much-needed HTTP header is stored. If you do not pass this header onto the InternetOpenUrl call, it will only allow you to open text files!

VOID* szTemp[16384];

 

This variable is a buffer in which 16 KB of data from the Internet file will be stored.

HINTERNET hConnect;

 

This is a HINTERNET handle containing the request result (from InternetOpenUrl).

FILE * pFile;

 

A standard C file handle(must include stdio.h). If you wish, you can use file APIs from Win32.

if (!(hConnect = InternetOpenUrlA (hOpen, szUrl, szHead, lstrlenA (szHead), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0)))

{

return INTERNET_ERROR_OPENURL;

}

 

With this call, you open a handle to the Internet file using a URL. The flags indicate that the file will always be read from the Internet rather than the cache. If it fails, the function returns an error. You can give INTERNET_ERROR_OPENURL any value you like. You have to define all these errors in order for this function to work. You can also replace it with a number.

if(!(pFile = fopen(szFileName, "wb" )))

{

return INTERNET_ERROR_FILEOPEN;

}

 

With this call, an attempt is made to open a file with the given file name. If it fails, another custom-defined error is returned.

DWORD dwByteToRead = 0;

DWORD dwSizeOfRq = 4;

DWORD dwBytes = 0;

 

These three variables will store the size of the file, the size of the HttpQueryInfo content, and the number of bytes read in total, respectively.

if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL))

{

dwByteToRead = 0;

}

 

With this call, an attempt is made to get the file's size. If the attempt fails, the dwByteToRead variable is set to 0, and no percentage or total size is displayed when the file is downloaded.

DWORD start;

DWORD end;

DWORD time;

time = 10;

start = timeGetTime();

 

For this bit, you will need to include mmsystem.h and link with the library winmm.lib, to allow these timing features. The timing features will tell the user how fast the download is. Using this example, only the Internet download speed will be stated. However, you can expand this functionality to estimate the time remaining as well.

do

{

if (!InternetReadFile(hConnect, szTemp, 16384, &dwSize))

{

fclose (pFile);

return INTERNET_ERROR_READFILE;

}

 

With this part, a loop begins in which the file is downloaded in 16 KB chunks. If the download request fails, the file is closed, and an error is returned.

if (!dwSize)

break;

else

fwrite(szTemp, sizeof(char), dwSize, pFile);

 

If dwSize is 0, it means EOF has been encountered, so the loop exits. Otherwise, the contents of the data read by InternetReadFile are written to the local file.

dwBytes+=dwSize;

if(dwByteToRead && hwndProgress)

{

SendDlgItemMessageA(hwndProgress, idProgressBar, WM_USER+2, (dwBytes*100)/dwByteToRead, 0);

UpdateWindow(hwndProgress);

}

 

With this code, dwBytes increases by the amount of data read from the file, and if the file's length is valid, and a progress window handle was specified, the progress bar is updated to indicate the download's progress.

FLOAT fSpeed = 0;

fSpeed = (float)dwBytes;

fSpeed /= ((float)time)/1000.0f;

fSpeed /= 1024.0f;

 

With this bit of code, the speed of the download is calculated based on the time it took, and the amount of data read.

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);

}

 

With this code, the status text of the progress window is set to indicate the download size and the speed of the download.

end = timeGetTime();

time = end - start;

if(time == 0)

time = 10;

 

The time is updated.

 

} // do

while (TRUE);

 

The loop ends.

fflush (pFile);

fclose (pFile);

return 0;

}

 

And finally, our function ends, closing the file and flushing the buffer to the hard drive. It returns 0, meaning success.

And that's it! With this bit of code and knowledge you can finally download files from the Internet efficiently and reliably. The full code example will follow.

  1. /*  
  2.  
  3. INET.H  
  4.  
  5. Header containing InternetGetFile and a wrapper function, InternetDownloadFile which also makes the Internet connection.  
  6.  
  7. */  
  8.   
  9. #ifndef INET_H   
  10. #define INET_H   
  11. #ifndef WIN32_LEAN_AND_MEAN   
  12. #define WIN32_LEAN_AND_MEAN   
  13. #include <windows.h>   
  14. #endif   
  15. #include <stdio.h>   
  16. #include <wininet.h>   
  17. #include <mmsystem.h>   
  18.   
  19. enum  
  20. {   
  21.     INTERNET_ERROR_OPENURL=1,   
  22.     INTERNET_ERROR_FILEOPEN,   
  23.     INTERNET_ERROR_READFILE,   
  24.     INTERNET_ERROR_OPEN   
  25. };   
  26.   
  27. UINT InternetGetFile (HINTERNET IN hOpen, // Handle from InternetOpen()   
  28.                  CHAR *szUrl,        // Full URL   
  29.                  CHAR *szFileName,   
  30.                  HWND hwndProgress,   
  31.                  int idStatusText,   
  32.                  int idProgressBar)   
  33. {   
  34.        DWORD dwSize;   
  35.        CHAR   szHead[] = "Accept: */*\r\n\r\n";   
  36.        VOID* szTemp[16384];   
  37.        HINTERNET  hConnect;   
  38.        FILE * pFile;   
  39.   
  40.        if ( !(hConnect = InternetOpenUrlA ( hOpen, szUrl, szHead,   
  41.              lstrlenA (szHead), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0)))   
  42.        {   
  43.            return INTERNET_ERROR_OPENURL;   
  44.        }   
  45.   
  46.        if  ( !(pFile = fopen (szFileName, "wb" ) ) )   
  47.       {   
  48.           return INTERNET_ERROR_FILEOPEN;   
  49.       }   
  50.   
  51.     DWORD dwByteToRead = 0;   
  52.     DWORD dwSizeOfRq = 4;   
  53.     DWORD dwBytes = 0;   
  54.   
  55.         if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,    
  56.                       (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL))   
  57.         {   
  58.         dwByteToRead = 0;   
  59.     }   
  60.     DWORD start;   
  61.     DWORD end;   
  62.     DWORD time;   
  63.     time = 10;   
  64.     start = timeGetTime();   
  65.        do  
  66.        {   
  67.           // Keep coping in 16 KB chunks, while file has any data left.   
  68.           // Note: bigger buffer will greatly improve performance.   
  69.           if (!InternetReadFile (hConnect, szTemp, 16384,  &dwSize) )   
  70.           {   
  71.               fclose (pFile);   
  72.             return INTERNET_ERROR_READFILE;   
  73.           }   
  74.           if (!dwSize)   
  75.               break;  // Condition of dwSize=0 indicate EOF. Stop.   
  76.           else  
  77.              fwrite(szTemp, sizeof (char), dwSize , pFile);   
  78.     dwBytes+=dwSize;   
  79.     if(dwByteToRead && hwndProgress)   
  80.     {   
  81.     SendDlgItemMessageA(hwndProgress, idProgressBar, WM_USER+2, (dwBytes*100)/dwByteToRead, 0);   
  82.     UpdateWindow(hwndProgress);   
  83.     }   
  84.     FLOAT fSpeed = 0;   
  85.     fSpeed = (float)dwBytes;   
  86.     fSpeed /= ((float)time)/1000.0f;   
  87.     fSpeed /= 1024.0f;   
  88.     if(hwndProgress)   
  89.     {   
  90.         char s[260];   
  91.         sprintf(s, "%d KB / %d KB @ %1.1f KB/s", dwBytes/1024, dwByteToRead/1024, fSpeed);   
  92.         SetDlgItemTextA(hwndProgress, idStatusText, s);   
  93.         UpdateWindow(hwndProgress);   
  94.     }   
  95.     end = timeGetTime();   
  96.     time = end - start;   
  97.     if(time == 0)   
  98.     time = 10;   
  99.        }   // do   
  100.       while (TRUE);   
  101.       fflush (pFile);   
  102.       fclose (pFile);   
  103.       return 0;   
  104. }   
  105.   
  106. int InternetDownloadFile(HWND progressWindow, int idStatusText, int idProgressBar, char *URL, char *FileDest)   
  107. {   
  108. DWORD dwFlags;   
  109. DWORD dwResult = INTERNET_ERROR_OPEN;   
  110. InternetGetConnectedState(&dwFlags, 0);   
  111. if(dwFlags & INTERNET_CONNECTION_OFFLINE)//take appropriate steps   
  112.     return INTERNET_ERROR_OPEN;   
  113. CHAR strAgent[64];   
  114. sprintf(strAgent, "Agent%ld", timeGetTime());   
  115. HINTERNET hOpen;   
  116. if(!(dwFlags & INTERNET_CONNECTION_PROXY))   
  117. hOpen = InternetOpenA(strAgent, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0);   
  118. else  
  119. hOpen = InternetOpenA(strAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);   
  120. if(hOpen)   
  121. {   
  122.     dwResult = InternetGetFile(hOpen, URL, FileDest, progressWindow, idStatusText, idProgressBar);   
  123.     InternetCloseHandle(hOpen);   
  124. }   
  125. else return INTERNET_ERROR_OPEN;   
  126. return dwResult;   
  127. }   
  128.   
  129. #endif /*INET_H*/  
  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓