📄 chap5.lst
字号:
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 + -