2017-06-10 72 views
0

我一直致力於使用WinHTTP和WinInet的HTTP客戶端,並且最近考慮切換到POCO,因爲它爲HTTP實現提供了最好的API。通過HTTPS從POCO StreamCopier獲取文件下載進度

我做了它的工作,但問題是我想通過定期查詢流或通過某些事件處理知道文件的下載進度。

開始搜索可以做到這一點的API,然後遇到了這個Http upload with progress info, in C++ (Poco/Boost),談到使用CountingOutputStream獲取文件上傳場景的進度。我覺得這是不完整的,並沒有按照我的預期那樣做,根本沒有使用CountingStream的實際實現。

我知道可以通過CountingInputStream實現,但我不知道如何通過HttpStreamFactory打開的調用返回流。是否有可能使用它讀取多個塊中的流?或者定期查詢讀取的數據量,以便我可以通知UI?

這是我的代碼:

bool HttpClientConnection::DownloadFile (const std::string& file_url, const std::string file_location) 
{ 

     try 
     { 
       std::string complete_page_url = ""; 
       std::ofstream file_stream; 
       std::unique_ptr<std::istream> pStr  = nullptr; 


       if (isSecureConnection) 
       { 
        complete_page_url = "https://"; 
       } 
       else 
       { 
        complete_page_url = "http://"; 
       } 


       { 
        complete_page_url = serverHostName + file_url;// assuming the file url itself will contain leading forward slash 
       } 


      // Create the URI from the URL to the file. 
      URI uri(complete_page_url); 

       //std::auto_ptr<std::istream>pStr(URIStreamOpener::defaultOpener().open(uri); 
      //StreamCopier::copyStream(*pStr.get(), std::cout); 

      if (isSecureConnection) 
      { 
        std::unique_ptr<HTTPSStreamFactory> https_stream_factory = nullptr; 

        if (_buseProxy) 
        { 
         https_stream_factory = std::unique_ptr<HTTPSStreamFactory>(new HTTPSStreamFactory(proxyHostName, proxyPort, getProxyUserName(), getProxyPassword())); 
        } 
        else 
        { 
         https_stream_factory = std::unique_ptr<HTTPSStreamFactory>(new HTTPSStreamFactory()); 
        } 

        if (https_stream_factory) 
        { 
         pStr = std::unique_ptr<std::istream>(https_stream_factory->open(uri)); 
        } 
       } 
       else 
       { 
        std::unique_ptr<HTTPStreamFactory> http_stream_factory = nullptr; 

        if (_buseProxy) 
        { 
         http_stream_factory = std::unique_ptr<HTTPStreamFactory>(new HTTPStreamFactory(proxyHostName, proxyPort, getProxyUserName(), getProxyPassword())); 
        } 
        else 
        { 
         http_stream_factory = std::unique_ptr<HTTPStreamFactory>(new HTTPStreamFactory()); 
        } 

        if (http_stream_factory) 
        { 
         pStr = std::unique_ptr<std::istream>(http_stream_factory->open(uri)); 
        } 
      } 

      if (pStr) 
      { 
        file_stream.open(file_location, ios::out | ios::trunc | ios::binary); 

        StreamCopier::copyStream(*pStr.get(), file_stream); 

        file_stream.close(); 
      } 

      return true; 
} 
catch (Exception& exc) 
{ 
    if (httpLogger) 
    { 
             httpLogger->log(dcLogger::LOG_INFO, "HttpClient:: Exception in DownloadFile , error code: %d", exc.code()); 
    } 
} 

return false; 

}

回答

0

傳遞在FileOutput流對象CountingOutputStream,並開始與計數輸出流作爲參數的計時器。定時器會被週期性地調用,直到數據傳輸完成並獲得寫入的字節數並通知註冊該事件的人。這工作!

shared_ptr<CountingOutputStream> cout_stream = shared_ptr<CountingOutputStream>(new CountingOutputStream(file_stream)); 

if (callback && callback_interval_in_millis > 0) 
{ 
    shared_ptr<FileProgressHandler> file_progress = shared_ptr<FileProgressHandler>(new FileProgressHandler(cout_stream, file_size, callback)); 

    if (file_progress) 
    { 
     TimerCallback<FileProgressHandler> callback(*(file_progress.get()), &FileProgressHandler::onTimer); 

     timer = shared_ptr<Timer>(new Timer(0, callback_interval_in_millis)); 

     if (timer) 
     { 
      timer->start(callback); 
     } 
    } 

    StreamCopier::copyStream(*pStr.get(), *cout_stream); 

    if (timer) 
    { 
     timer->stop(); 
    } 
} 

void onTimer(Timer& timer) 
{ 
    try 
    { 
     if (progress_callback) 
     { 
      int data_processed = 0; 

      counting_io_stream ? data_processed = counting_io_stream->chars() : __noop; 

      if (data_processed != total_processed_data) 
      { 
       total_processed_data = data_processed; 

       int percent  = (100 * total_processed_data)/file_size; 

       progress_callback(percent); 
      } 
     } 
    } 
    catch(const std::bad_function_call& e) 
    { 

    } 
    catch(const std::bad_weak_ptr& e) 
    { 

    } 
    catch(const std::exception& e) 
    { 

    } 
}