⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap5.lst

📁 The Art of C++一书的配套源代码
💻 LST
📖 第 1 页 / 共 2 页
字号:
listing 1
// A file download subsystem.  
#include <iostream>  
#include <windows.h>  
#include <wininet.h>  
#include <fstream>  
#include <cstdio>  
  
using namespace std;  
  
const int MAX_ERRMSG_SIZE = 80;  
const int MAX_FILENAME_SIZE = 512;  
const int BUF_SIZE = 1024;  
  
// Exception class for download errors.  
class DLExc {  
  char err[MAX_ERRMSG_SIZE];  
public:  
  DLExc(char *exc) {  
    if(strlen(exc) < MAX_ERRMSG_SIZE)  
      strcpy(err, exc);  
  }  
  
  // Return a pointer to the error message.  
  const char * geterr() {  
    return err;  
  }  
};  
  
// A class for downloading files from the Internet.  
class Download {  
  static bool ishttp(char *url);  
  static bool httpverOK(HINTERNET hIurl);  
  static bool getfname(char *url, char *fname);  
  static unsigned long openfile(char *url, bool reload,  
                                ofstream &fout);  
public:  
  static bool download(char *url, bool restart=false,  
     void (*update)(unsigned long, unsigned long)=NULL);  
};  
  
  
// Download a file.   
//  
// Pass the URL of the file to url.  
//  
// To reload a file, pass true to reload.  
//  
// To specify an update function that is called after  
// each buffer is read, pass a pointer to that  
// function as the third parameter.  If no update  
// function is desired, then let the third parameter  
// default to null.  
bool Download::download(char *url, bool reload,   
       void (*update)(unsigned long, unsigned long)) {  
  
  ofstream fout;           // output stream  
  unsigned char buf[BUF_SIZE]; // input buffer  
  unsigned long numrcved;  // number of bytes read  
  unsigned long filelen;   // length of file on disk  
  HINTERNET hIurl, hInet;  // Internet handles  
  unsigned long contentlen;// length of content  
  unsigned long len;       // length of contentlen  
  unsigned long total = 0; // running total of bytes received  
  char header[80];         // holds Range header  
  
  try {  
    if(!ishttp(url))  
      throw DLExc("Must be HTTP url.");  
  
    // Open the file specified by url.  
    // The open stream will be returned  
    // in fout.  If reload is true, then  
    // any preexisting file will be truncated.  
    // The length of any preexisting file (after   
    // possible truncation) is returned.  
    filelen = openfile(url, reload, fout);  
  
    // See if Internet connection available.  
    if(InternetAttemptConnect(0) != ERROR_SUCCESS)   
      throw DLExc("Can't connect.");  
  
    // Open Internet connection.  
    hInet = InternetOpen("downloader",  
                        INTERNET_OPEN_TYPE_DIRECT,  
                        NULL, NULL,  0);  
  
    if(hInet == NULL)   
      throw DLExc("Can't open connection.");  
  
    // Construct header requesting range of data.  
    sprintf(header, "Range:bytes=%d-", filelen);   
  
    // Open the URL and request range.  
    hIurl = InternetOpenUrl(hInet, url,  
              header, -1,  
              INTERNET_FLAG_NO_CACHE_WRITE, 0);  
  
    if(hIurl == NULL) throw DLExc("Can't open url.");  
  
    // Confirm that HTTP/1.1 or greater is supported.  
    if(!httpverOK(hIurl))  
      throw DLExc("HTTP/1.1 not supported.");  
     
    // Get content length.  
    len = sizeof contentlen;  
    if(!HttpQueryInfo(hIurl,  
                      HTTP_QUERY_CONTENT_LENGTH |  
                      HTTP_QUERY_FLAG_NUMBER,  
                      &contentlen, &len, NULL))  
      throw DLExc("File or content length not found.");  
  
    // If existing file (if any) is not complete,  
    // then finish downloading.  
    if(filelen != contentlen && contentlen)   
      do {  
        // Read a buffer of info.  
        if(!InternetReadFile(hIurl, &buf,  
                             BUF_SIZE, &numrcved))  
          throw DLExc("Error occurred during download.");  
  
         // Write buffer to disk.  
         fout.write((const char *) buf, numrcved);  
         if(!fout.good())   
           throw DLExc("Error writing file.");  
       
         total += numrcved; // update running total  
  
         // Call update function, if specified.  
         if(update && numrcved > 0)  
           update(contentlen+filelen, total+filelen);  
  
      } while(numrcved > 0);  
    else  
      if(update)  
        update(filelen, filelen);  
  
  } catch(DLExc) {  
    fout.close();  
    InternetCloseHandle(hIurl);  
    InternetCloseHandle(hInet);  
  
    throw; // rethrow the exception for use by caller  
  }  
  
  fout.close();  
  InternetCloseHandle(hIurl);  
  InternetCloseHandle(hInet);  
  
  return true;  
}  
  
// Return true if HTTP version of 1.1 or greater.  
bool Download::httpverOK(HINTERNET hIurl) {  
  char str[80];  
  unsigned long len = 79;  
  
  // Get HTTP version.  
  if(!HttpQueryInfo(hIurl, HTTP_QUERY_VERSION, &str, &len, NULL))  
    return false;  
 
  // First, check major version number.  
  char *p = strchr(str, '/'); 
  p++; 
  if(*p == '0') return false; // can use HTTP 0.x 
 
  // Now, find start of minor HTTP version number.  
  p = strchr(str, '.');  
  p++;  
  
  // Convert to int.  
  int minorVerNum = atoi(p);  
  
  if(minorVerNum > 0) return true;  
  return false;  
}  
  
// Extract the filename from the URL.  Return false if  
// the filename cannot be found.  
bool Download::getfname(char *url, char *fname) {  
  // Find last /.  
  char *p = strrchr(url, '/');  
  
  // Copy filename after the last /.   
  if(p && (strlen(p) < MAX_FILENAME_SIZE)) {  
    p++;  
    strcpy(fname, p);  
    return true;  
  }  
  else  
    return false;  
}  
  
// Open the output file, initialize the output  
// stream, and return the file's length.  If  
// reload is true, first truncate any preexisting  
// file.  
unsigned long Download::openfile(char *url,  
                                 bool reload,  
                                 ofstream &fout) {  
  char fname[MAX_FILENAME_SIZE];  
  
  if(!getfname(url, fname))   
    throw DLExc("File name error.");  
  
  if(!reload)   
    fout.open(fname, ios::binary | ios::out |  
                     ios::app | ios::ate);    
  else  
    fout.open(fname, ios::binary | ios::out |  
                     ios::trunc);    
  
  if(!fout)  
    throw DLExc("Can't open output file.");    
  
  // Get current file length.  
  return fout.tellp();  
}  
  
// Confirm that the URL specifies HTTP.  
bool Download::ishttp(char *url) {  
  char str[5] = "";  
  
  // Get first four characters from URL.  
  strncpy(str, url, 4);  
  
  // Convert to lowercase  
  for(char *p=str; *p; p++) *p = tolower(*p);  
    
  return !strcmp("http", str);  
}

listing 2
// Header file for downloader.  Call this file dl.h. 
#include <iostream> 
#include <string> 
#include <windows.h> 
#include <wininet.h> 
#include <fstream> 
using namespace std; 
 
const int MAX_ERRMSG_SIZE = 80; 
 
// Exception class for downloading errors. 
class DLExc { 
  char err[MAX_ERRMSG_SIZE]; 
public: 
  DLExc(char *exc) { 
    if(strlen(exc) < MAX_ERRMSG_SIZE) 
      strcpy(err, exc); 
  } 
 
  const char * geterr() { 
    return err; 
  } 
}; 
 
class Download { 
  static bool httpverOK(HINTERNET hIurl); 
  static bool getfname(char *url, char *fname); 
  static unsigned long openfile(char *url, bool reload, 
                                ofstream &fout); 
public: 
  static bool download(char *url, bool restart=false, 
    void (*update)(unsigned long, unsigned long)=NULL); 
};

listing 3
// A Sample program that uses Download. 
#include <iostream> 
#include "dl.h" 
 
// This function displays the download progress as a percentage. 
void showprogress(unsigned long total, unsigned long part) { 
  int val = (int) ((double) part/total*100); 
  cout << val << "%" << endl; 
} 
 
int main(int argc, char *argv[]) 
{ 
 
  // This URL is for demonstration purposes only.  Substitute 
  // the URL of the file that you want to download. 
  char url[] = 
   "http://www.osborne.com/products/0072226803/0072226803_code.zip"; 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -