1. 程式人生 > >MFC 下載網路檔案到本地 利用 CHttpFile 和 URLDownloadToFile 【可設超時及進度】兩種方式

MFC 下載網路檔案到本地 利用 CHttpFile 和 URLDownloadToFile 【可設超時及進度】兩種方式

說明

方法1較為簡單,通用的多,但在某些環境下可能出現未知錯誤(也有可能你碰不到,反正我是碰到了)。
方法2實現相對麻煩點,但可設定超時時間以及進度展示,但要例項化一個LPBINDSTATUSCALLBACK 子類,在這個子類中去實現。這個相對好用點,方法1遇到的錯誤的情況,用方法2卻可以正常使用。
LPBINDSTATUSCALLBACK 這個子類程式碼沒有貼出來,放在文未,可點選下載。

方法1 利用CHttpFile下載

函式如下:

void CHttpData::DownloadFile(CString strURL,CString strLocalPath) 
{
    const
int dwBufSize = 1024; CInternetSession* Session = new CInternetSession; CHttpFile* pHttpFile = NULL; CStdioFile pLocalFile; DWORD dwlen; LoggerCio::notice(LoggerCio::LOG_SYS,"*** CHttpData::DownloadFile"); LPBYTE lpBuf = new byte[dwBufSize]; if(FALSE == pLocalFile.Open(strLocalPath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { LoggerCio::notice(LoggerCio::LOG_SYS,"*** 下載檔案到本地失敗,沒有本地寫許可權"
); return; } //判斷檔案是否存在 HANDLE hFind; WIN32_FIND_DATA wfd; hFind=FindFirstFile(strLocalPath,&wfd); if(hFind != INVALID_HANDLE_VALUE){ //存在則刪除 DeleteFile(strLocalPath); LoggerCio::notice(LoggerCio::LOG_SYS,"delete the existing"); } FindClose(hFind); // 增加OpenURL保護
HINTERNET hOpen = InternetOpen (NULL,PRE_CONFIG_INTERNET_ACCESS,NULL, NULL, 0); HINTERNET hRequest = InternetOpenUrl (hOpen, strURL,NULL, 0, INTERNET_FLAG_TRANSFER_BINARY,0); if(!hRequest ){ delete[] lpBuf; lpBuf = NULL; LoggerCio::notice(LoggerCio::LOG_SYS,"*** 開啟strURL失敗"); return; } if( hOpen ) InternetCloseHandle(hOpen ); if(hRequest ) InternetCloseHandle(hRequest ); pHttpFile = (CHttpFile*)Session->OpenURL( strURL, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, NULL, 0); if (NULL == pHttpFile) { delete[] lpBuf; lpBuf = NULL; LoggerCio::notice(LoggerCio::LOG_SYS,"*** CHttpData::OpenURL返回值為空"); return; } DWORD dwStatusCode; pHttpFile->QueryInfoStatusCode(dwStatusCode); if (HTTP_STATUS_OK == dwStatusCode) { LoggerCio::notice(LoggerCio::LOG_SYS,"open url finish and HTTP_STATUS_OK"); while(dwlen = pHttpFile-> Read(lpBuf, dwBufSize-1 )) { pLocalFile.Write(lpBuf,dwlen); } LoggerCio::notice(LoggerCio::LOG_SYS,"*** file download finish"); pHttpFile->Close();//關閉CHttpFile 並釋放其資源。只有在對SendRequest的成功呼叫或者一個CHttpFile物件被 OpenURL成功建立後,才能使用該成員函式。 pHttpFile=NULL; } //資源回收 Session->Close(); pLocalFile.Close(); delete[] lpBuf; lpBuf = NULL; }

方法2 URLDownloadToFile (可設超時時間,顯示進度)

//strURL:網路地址,strLocalPath:要儲存的本地地址,nTimeOutSec:超時秒數
BOOL CHttpData::downloadFileByIe3(CString strURL,CString strLocalPath,int nTimeOutSec)
{
    CCallback callback;//派生自IBindStatusCallback的子類
    // If the user wants a timeout, calculate the time when the download
    // should abort.
    if ( nTimeOutSec > 0 )
    {
        callback.m_bUseTimeout = TRUE;
        callback.m_timeToStop = CTime::GetCurrentTime() + CTimeSpan( 0, 0, 0, nTimeOutSec );
    }

    HRESULT hr;
    hr = URLDownloadToFile ( NULL,      // ptr to ActiveX container
        strURL,      // URL to get
        strLocalPath,     // file to store data in
        0,         // reserved
        &callback  // ptr to IBindStatusCallback
        );

    if ( SUCCEEDED(hr) )
        return TRUE;
    else
    {
        LPTSTR lpszErrorMessage;
        CString sMsg;

        if ( FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM | 
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, hr, 
            MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            (LPTSTR) &lpszErrorMessage, 0, NULL ))
        {
            sMsg.Format ( _T("Download failed.  Error = 0x%08lX\n\n%s"),
                (DWORD) hr, lpszErrorMessage );
            LocalFree ( lpszErrorMessage );
        }
        else
        {
            sMsg.Format ( _T("Download failed.  Error = 0x%08lX\n\nNo message available."),
                (DWORD) hr );
        }

        OutputDebugStringW(sMsg);
        USES_CONVERSION;
        LoggerCio::notice(LoggerCio::LOG_SYS,"%s",T2A(sMsg));
        return FALSE;
    }
}