尝试过几个方法:
1、直接socket实现http下载
此方法实现太复杂,需要非常熟悉tcp/ip协议栈,短时间很难实现稳定下载。
2、Windows API的URLDownloadToFile
这个方法是最简单,一个函数就搞定一切。
但是缺点也很多:
函数依赖IE。还好,从IE3.0就已经开始支持这个函数功能,而且IE是捆绑Windows的,所以这个缺点可以忽略。
实现进度条困难。虽然有一个回调函数可以解决这个问题,需要重载一个模板类。
最大的缺点是太简单,下载过程不能很好控制,稳定性跟IE一样……
3、利用WinInet
协议支持HTTP/FTP/Gopher,实现简单,过程可控,是最佳选择。
下面是一个简单的实现代码:
//创建 CInternetSession对象,初始化WinInet,并连接服务器
m_pInetSession=new CInternetSession(NULL
,1
,INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD);
//设置参数
m_pInetSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000,1);
m_pInetSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000);
m_pInetSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,1);
//打开URL文件,返回CStdioFile
pSFile = m_pInetSession->OpenURL( http://hd61.15150.com/music/2006_8_6/212030_165807_05152.mp3);
//缓冲区
BYTE pBuf[1024] = {NULL};
CFile pCFile = NULL;
//创建本地文件
pCFile.Open("c://1.mp3",
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
//从缓冲区循环读取文数据
while ( int bytesread = pSFile->Read(pBuf,1024))
{
//指针移到文件结尾
pCFile.SeekToEnd();
//将读取的缓冲区数据写入本地文件
pCFile.Write(pBuf, bytesread);
}
//关闭本地文件
pCFile.Close();
//关闭CStdioFile
pSFile->Close();
}
catch(CInternetException* lpEx)
{
lpEx->ReportError();
lpEx->Delete();
delete m_pInetSession;
}
AfxMessageBox("下载完成");
函数解释
1,CInternetSession(LPCTSTR pstrAgent = NULL, DWORD dwContext = 1,
DWORD dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG,
LPCTSTR pstrProxyName = NULL, LPCTSTR pstrProxyBypass = NULL,
DWORD dwFlags = 0 );
pstrAgent 指向字符串的指针,标识调用Internet函数应用或入口名(例如,“Microsoft Internet Browser”)。如果 pstrAgent 为NULL (缺省),框架调用全局函数AfxGetAppName,返回一个包含应用名的空终止字符串。一些协议使用此字符串来对服务器标识应用。
dwContext 操作的上下文标识符。dwContext标识由CInternetSession::OnStatusCallback返回的状态信息。缺省设置为1;但是,你可为操作明确指定一个指定的上下文ID。对象及其所做的任何工作将与此上下文ID有关。如果dwFlags包括INTERNET_FLAG_ASYNC,由此对象创建的对象在状态回调例程注册后即具备异步行为。为了使一个函数同步结束,dwContext必须为此调用设置为0。
dwAccessType 访问所需的类型。下列值是有效值,仅仅提供其中一个: ·
INTERNET_OPEN_TYPE_PRECONFIG 预配置(登录时)。此访问类型设作缺省的。
· INTERNET_OPEN_TYPE_DIRECT 直接面向Internet。
· INTERNET_OPEN_TYPE_PROXY 通过CERN代理。
pstrProxyName 若dwAccessType设置为INTERNET_OPEN_TYPE_PROXY,建议的CERN代理名。缺省为NULL。
pstrProxyBypass 指向包含服务器地址选项列表的字符串的指针。使用代理访问时,这些地址可能会被忽略。如果提供NULL值,忽略列表将从登录中读取。此参数只在dwAccessType设置为INTERNET_OPEN_TYPE_PROXY时才有意义。
dwFlags 指示不同的选项,如缓存和异步行为。缺省设置为0。
可能值包括: ·
INTERNET_FLAG_DONT_CACHE 不缓存数据,既在本地,也不在任何网关服务器中。
INTERNET_FLAG_ASYNC 将来对此对象的操作可能失败,返回ERROR_IO_PENDING。操作结束时,状态回调将与INTERNET_STATUS_ REQUEST_COMPLETE一起生成。此回调是线程的,而不是某个原始请求。必须调用EnableStatusCallback来建立一个状态回调例程,否则函数将同步完成。
INTERNET_FLAG_OFFLINE 下载操作只适用于永久性缓存。如果此项不存在于缓存中,将返回适当的错误代码。此标记可能用位或OR(|)操作符组合。
说明:
当一个CInternetSession对象被创建时,此成员函数被调用。
CInternetSession是被应用调用的第一个Internet函数。它初始化内部数据结构并为将来来自应用的调用做准备。
如果dwFlags包括INTERNET_FLAG_ASYNC,由此对象创建的对象在状态回调例程注册后即具备异步行为。
如果没有Internet连接能被打开,则CInternetSession产生一个AfxThrowInternetException
2,CInternetSession::SetOption
BOOL SetOption( DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength );
BOOL SetOption( DWORD dwOption, DWORD dwValue );
返回值:
如果操作成功,则返回一个TRUE值。如果出错,返回一个FALSE值。如果调用失败,Win32函数GetLastError将被调用,以确定出错原因。
参数: dwOption 请参阅CInternetSession::QueryOption得到可能值的列表。
lpBuffer 包含选项设置的缓冲区。
dwBufferLength lpBuffer长度或dwValue大小。
dwValue 包含选项设置的DWORD。
说明:
调用此成员函数以设置Internet会话的选项。
3,CStdioFile
CStdioFile继承自CFile,一个CStdioFile 对象代表一个用运行时函数fopen 打开的C 运行时流式文件。
流式文件是被缓冲的,而且可以以文本方式(缺省)或二进制方式打开。文本方式提供对硬回车—换行符对的特殊处理。当你将一个换行符(0x0A)写入一个文本方式的CStdioFile 对象时,字节对(0x0D,0x0A)被发送给该文件。当你读一个文件时,字节对(0x0D,0x0A)被翻译为一个字节(0x0A)。
CStdioFile 不支持Duplicate,LockRange,和UnlockRange 这几个CFile 函数。如果在CStdioFile 中调用了这几个函数,将会出现CNoSupported 异常。
CStdioFile::ReadString(LPTSTR lpsz, UINT nMax);
读取一行文本到缓冲区,遇到“0x0D,0x0A”时停止读取,并且去掉硬回车“0x0D”,保留换行符“0x0A”,在字符串末尾添加“/0”(0x00)。nMax个字符里包含0x00这个字符。分析如下:
1)如果nMax <= 字符数,读取(nMax-1)个字符 + 0x00
2)如果nMax = 字符数 + 1,读取nMax个字符 + 0x00
3)如果nMax > 字符数,读取nMax个字符 + 0x0A + 0x00
CStdioFile::ReadString(CString &rString);(重载)
读取一行文本到rString,遇到回车换行符停止读取。回车和换行符不读到rString,而且末尾也没有添加“/0”。
CStdioFile::WriteString( LPCTSTR lpsz );(不支持CString直接写入)
将一个缓冲区中的数据写入与CStdioFile 对象关联的文件中。需要给字符串lpsz的末尾加上换行标志”/r/n”。结束的空字符(“/0”)不被写入该文件。lpsz 中的所有换行符都被以一个硬回车换行符对写入该文件,即“/n”被转化成“/r/n”写入到文件里。
比如:写入文件的例子
CStdioFile file; //创建文件
file.Open("ts.txt",CFile::modeCreate|CFile::modeWrite); //写入文件
CString str;
str.Format("%s/r/n","hello!I am talkingmute!");
file.Seek(0,CFile::end);
file.WriteString( str );
file.Close();//关闭文件
比如:读文件的例子
CString strText = “”; CString szLine = “”;
CStdioFile file;
file.Open("ts.txt",CFile::modeRead); //打开文件
while( file.ReadString( szLine ) ) //逐行读取字符串
{ strText += szLine; }
MessageBox(strText);
file.Close(); //关闭文件
1、直接socket实现http下载
此方法实现太复杂,需要非常熟悉tcp/ip协议栈,短时间很难实现稳定下载。
2、Windows API的URLDownloadToFile
这个方法是最简单,一个函数就搞定一切。
但是缺点也很多:
函数依赖IE。还好,从IE3.0就已经开始支持这个函数功能,而且IE是捆绑Windows的,所以这个缺点可以忽略。
实现进度条困难。虽然有一个回调函数可以解决这个问题,需要重载一个模板类。
最大的缺点是太简单,下载过程不能很好控制,稳定性跟IE一样……
3、利用WinInet
协议支持HTTP/FTP/Gopher,实现简单,过程可控,是最佳选择。
下面是一个简单的实现代码:
//创建 CInternetSession对象,初始化WinInet,并连接服务器
m_pInetSession=new CInternetSession(NULL
,1
,INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD);
//设置参数
m_pInetSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000,1);
m_pInetSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000);
m_pInetSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,1);
//打开URL文件,返回CStdioFile
pSFile = m_pInetSession->OpenURL( http://hd61.15150.com/music/2006_8_6/212030_165807_05152.mp3);
//缓冲区
BYTE pBuf[1024] = {NULL};
CFile pCFile = NULL;
//创建本地文件
pCFile.Open("c://1.mp3",
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
//从缓冲区循环读取文数据
while ( int bytesread = pSFile->Read(pBuf,1024))
{
//指针移到文件结尾
pCFile.SeekToEnd();
//将读取的缓冲区数据写入本地文件
pCFile.Write(pBuf, bytesread);
}
//关闭本地文件
pCFile.Close();
//关闭CStdioFile
pSFile->Close();
}
catch(CInternetException* lpEx)
{
lpEx->ReportError();
lpEx->Delete();
delete m_pInetSession;
}
AfxMessageBox("下载完成");
函数解释
1,CInternetSession(LPCTSTR pstrAgent = NULL, DWORD dwContext = 1,
DWORD dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG,
LPCTSTR pstrProxyName = NULL, LPCTSTR pstrProxyBypass = NULL,
DWORD dwFlags = 0 );
pstrAgent 指向字符串的指针,标识调用Internet函数应用或入口名(例如,“Microsoft Internet Browser”)。如果 pstrAgent 为NULL (缺省),框架调用全局函数AfxGetAppName,返回一个包含应用名的空终止字符串。一些协议使用此字符串来对服务器标识应用。
dwContext 操作的上下文标识符。dwContext标识由CInternetSession::OnStatusCallback返回的状态信息。缺省设置为1;但是,你可为操作明确指定一个指定的上下文ID。对象及其所做的任何工作将与此上下文ID有关。如果dwFlags包括INTERNET_FLAG_ASYNC,由此对象创建的对象在状态回调例程注册后即具备异步行为。为了使一个函数同步结束,dwContext必须为此调用设置为0。
dwAccessType 访问所需的类型。下列值是有效值,仅仅提供其中一个: ·
INTERNET_OPEN_TYPE_PRECONFIG 预配置(登录时)。此访问类型设作缺省的。
· INTERNET_OPEN_TYPE_DIRECT 直接面向Internet。
· INTERNET_OPEN_TYPE_PROXY 通过CERN代理。
pstrProxyName 若dwAccessType设置为INTERNET_OPEN_TYPE_PROXY,建议的CERN代理名。缺省为NULL。
pstrProxyBypass 指向包含服务器地址选项列表的字符串的指针。使用代理访问时,这些地址可能会被忽略。如果提供NULL值,忽略列表将从登录中读取。此参数只在dwAccessType设置为INTERNET_OPEN_TYPE_PROXY时才有意义。
dwFlags 指示不同的选项,如缓存和异步行为。缺省设置为0。
可能值包括: ·
INTERNET_FLAG_DONT_CACHE 不缓存数据,既在本地,也不在任何网关服务器中。
INTERNET_FLAG_ASYNC 将来对此对象的操作可能失败,返回ERROR_IO_PENDING。操作结束时,状态回调将与INTERNET_STATUS_ REQUEST_COMPLETE一起生成。此回调是线程的,而不是某个原始请求。必须调用EnableStatusCallback来建立一个状态回调例程,否则函数将同步完成。
INTERNET_FLAG_OFFLINE 下载操作只适用于永久性缓存。如果此项不存在于缓存中,将返回适当的错误代码。此标记可能用位或OR(|)操作符组合。
说明:
当一个CInternetSession对象被创建时,此成员函数被调用。
CInternetSession是被应用调用的第一个Internet函数。它初始化内部数据结构并为将来来自应用的调用做准备。
如果dwFlags包括INTERNET_FLAG_ASYNC,由此对象创建的对象在状态回调例程注册后即具备异步行为。
如果没有Internet连接能被打开,则CInternetSession产生一个AfxThrowInternetException
2,CInternetSession::SetOption
BOOL SetOption( DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength );
BOOL SetOption( DWORD dwOption, DWORD dwValue );
返回值:
如果操作成功,则返回一个TRUE值。如果出错,返回一个FALSE值。如果调用失败,Win32函数GetLastError将被调用,以确定出错原因。
参数: dwOption 请参阅CInternetSession::QueryOption得到可能值的列表。
lpBuffer 包含选项设置的缓冲区。
dwBufferLength lpBuffer长度或dwValue大小。
dwValue 包含选项设置的DWORD。
说明:
调用此成员函数以设置Internet会话的选项。
3,CStdioFile
CStdioFile继承自CFile,一个CStdioFile 对象代表一个用运行时函数fopen 打开的C 运行时流式文件。
流式文件是被缓冲的,而且可以以文本方式(缺省)或二进制方式打开。文本方式提供对硬回车—换行符对的特殊处理。当你将一个换行符(0x0A)写入一个文本方式的CStdioFile 对象时,字节对(0x0D,0x0A)被发送给该文件。当你读一个文件时,字节对(0x0D,0x0A)被翻译为一个字节(0x0A)。
CStdioFile 不支持Duplicate,LockRange,和UnlockRange 这几个CFile 函数。如果在CStdioFile 中调用了这几个函数,将会出现CNoSupported 异常。
CStdioFile::ReadString(LPTSTR lpsz, UINT nMax);
读取一行文本到缓冲区,遇到“0x0D,0x0A”时停止读取,并且去掉硬回车“0x0D”,保留换行符“0x0A”,在字符串末尾添加“/0”(0x00)。nMax个字符里包含0x00这个字符。分析如下:
1)如果nMax <= 字符数,读取(nMax-1)个字符 + 0x00
2)如果nMax = 字符数 + 1,读取nMax个字符 + 0x00
3)如果nMax > 字符数,读取nMax个字符 + 0x0A + 0x00
CStdioFile::ReadString(CString &rString);(重载)
读取一行文本到rString,遇到回车换行符停止读取。回车和换行符不读到rString,而且末尾也没有添加“/0”。
CStdioFile::WriteString( LPCTSTR lpsz );(不支持CString直接写入)
将一个缓冲区中的数据写入与CStdioFile 对象关联的文件中。需要给字符串lpsz的末尾加上换行标志”/r/n”。结束的空字符(“/0”)不被写入该文件。lpsz 中的所有换行符都被以一个硬回车换行符对写入该文件,即“/n”被转化成“/r/n”写入到文件里。
比如:写入文件的例子
CStdioFile file; //创建文件
file.Open("ts.txt",CFile::modeCreate|CFile::modeWrite); //写入文件
CString str;
str.Format("%s/r/n","hello!I am talkingmute!");
file.Seek(0,CFile::end);
file.WriteString( str );
file.Close();//关闭文件
比如:读文件的例子
CString strText = “”; CString szLine = “”;
CStdioFile file;
file.Open("ts.txt",CFile::modeRead); //打开文件
while( file.ReadString( szLine ) ) //逐行读取字符串
{ strText += szLine; }
MessageBox(strText);
file.Close(); //关闭文件