zoukankan      html  css  js  c++  java
  • 如何使用 WinInet 时提供下载上载进度信息

    概要
    许多开发人员都使用 WinInet 函数来下载或上载文件在 Internet 上的想要提供一个进度条以指示多少文件传输已完成,但多少就越长。您可以使用以下机制来完成此。
    Collapse image更多信息
    使用 InternetSetStatusCallback 来获取下载进度的通知为您提供良好的信息请求的进展如何,包括连接状态通知。但是,它不表示一定百分比的传输已完成。

    若要获取的百分比相当完整的通知,您需要确定传输的大小,然后使用小缓冲区中调用 InternetReadFile 或 InternetWriteFile。然后,您可以作为完整的函数调用来计算传输的百分比。

    例如,假设您想要下载的 1000 个字节的文件。而不是进行一次调用 InternetReadFile 1000 字节的缓冲区,可以拨打 10 InternetReadFIle 与 100 字节的缓冲区。通过这种方式完成每次调用 InternetReadFile,您知道下载是另一个完整的 10%。

    下面的代码说明了此过程:

    #include<windows.h>
    #include<wininet.h>
    #include<iostream.h>
    
    void main(int argc, char *argv[])
    {
        if (argc != 3)
        {
            cout << "Usage: progress <host> <object>" << endl;
            return;
        }
    
        HINTERNET hSession = InternetOpen("WinInet Progress Sample",
                                          INTERNET_OPEN_TYPE_PRECONFIG,
                                          NULL,
                                          NULL,
                                          0);
        HINTERNET hConnection = InternetConnect(hSession,
                                                argv[1],  // Server
                                                INTERNET_DEFAULT_HTTP_PORT,
                                                NULL,     // Username
                                                NULL,     // Password
                                                INTERNET_SERVICE_HTTP,
                                                0,        // Synchronous
                                                NULL);    // No Context
    
        HINTERNET hRequest = HttpOpenRequest(hConnection,
                                             "GET",
                                             argv[2],
                                             NULL,    // Default HTTP Version
                                             NULL,    // No Referer
                                             (const char**)"*/*", // Accept
                                                                    // anything
                                             0,       // Flags
                                             NULL);   // No Context
        HttpSendRequest(hRequest,
                        NULL,    // No extra headers
                        0,       // Header length
                        NULL,    // No Body
                        0);      // Body length
    
        DWORD dwContentLen;
        DWORD dwBufLen = sizeof(dwContentLen);
        if (HttpQueryInfo(hRequest,
                          HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
                          (LPVOID)&dwContentLen,
                          &dwBufLen,
                          0))
        {
            // You have a content length so you can calculate percent complete
            char *pData = (char*)GlobalAlloc(GMEM_FIXED, dwContentLen + 1);
            DWORD dwReadSize = dwContentLen / 10;   // We will read 10% of data
                                                    // with each read.
    
            cout << "Download Progress:" << endl;
            cout << "    0----------100%" << endl;
            cout << "     ";
            cout.flush();
    
            DWORD cReadCount;
            DWORD dwBytesRead;
            char *pCopyPtr = pData;
            for (cReadCount = 0; cReadCount < 10; cReadCount++)
            {
                InternetReadFile(hRequest, pCopyPtr, dwReadSize, &dwBytesRead);
                cout << "*";
                cout.flush();
                pCopyPtr = pCopyPtr + dwBytesRead;
            }
            // extra read to account for integer division round off
            InternetReadFile(hRequest,
                             pCopyPtr,
                             dwContentLen - (pCopyPtr - pData),
                             &dwBytesRead);
            // Null terminate data
            pData[dwContentLen] = 0;
    
            // Display
            cout << endl << "Download Complete" << endl;
            cout << pData;
        }
        else
        {
            DWORD err = GetLastError();
            // No content length...impossible to calculate % complete
            // Just read until we are done.
            char pData[100];
            DWORD dwBytesRead = 1;
            while (dwBytesRead)
            {
                InternetReadFile(hRequest, pData, 99, &dwBytesRead);
                pData[dwBytesRead] = 0;
                cout << pData;
            }
        }
    }
    


                    

    有几点需要注意的使用这种方法时:

        在开始之前,您必须知道的数据大小。上面的代码将尝试通过阅读使用 HttpQueryInfo 函数的 HTTP 内容长度标头来确定数据大小。尽管许多 HTTP 响应中包括的内容长度标头,则不需要。除非您有另一种机制,用于获取数据的大小,您将不能计算进度,如果在响应中未包括的内容长度标头。
        如果您试图上载或下载 FTP 资源中,您将不能使用 FtpPutFile 或 FtpGetFile,并希望确定进度信息。您应该使用 FtpOpenFile,然后使用 InternetReadFile 和 InternetWriteFile,如上面所述。
        因为提供进度的信息假定您必须知道数据的大小,可以使用 FtpGetFileSize 来下载文件之前获取 FTP 资源的大小。请注意 FtpGetFileSize 并不总是成功由于多种 FTP 服务器返回目录列表信息的方式获取的文件大小。有关使用 FTP 来获取目录列表信息的问题的其他信息,请参阅下面 Microsoft 知识库中相应的文章:
        172712信息: 限制的 WinInet FTP 功能

  • 相关阅读:
    HTTP协议
    jQuery中的事件模型
    AJAX请求 load方法的使用
    jQuery让页面动起来
    jQuery中的事件传播
    jQuery包装集和DOM对象
    CentOS 7 添加网卡后没有对应网卡配置文件解决方法
    openstack高可用集群搭建(集中式路由)(train版)
    5大富文本编辑器比较
    委托和事件:
  • 原文地址:https://www.cnblogs.com/microzone/p/3383236.html
Copyright © 2011-2022 走看看