一个客户端程序采用 winInet API开发的, 从http服务器上下载一个文件, 希望下载后直接打开,而不是保存.
我的想法是采用临时文件, 每次用InternetReadFile () 从服务器上下载一小块数据(比如4k), 下载后写入文件, 下载完毕后打开该临时文件.
现在的问题: windows的临时文件如何生成不太清楚(windows api方面比较弱) . 而且如果下载中途突然退出程序, 如何能保证该临时文件被删除?还有另外一个类似的问题, 下载一大块大小不定的数据, 然后对数据进行分析.
 问题是: 由于大小不固定,而且事先无法得知,无法事先分配buffer, 下载的时候可以循环每次下载4k小块, 但却难以找到一个大的buffer来把整个数据块装载进去.  这个问题如何解决? 最好不用临时文件,直接在内存中操作.大家可以给出好的点子和建议,最好有代码,谢谢了

解决方案 »

  1.   

    这有一个例子,希望对你有帮助
    #include   <stdio.h>  
      #include   <wininet.h>  
      #include   <mmsystem.h>  
       
      enum  
      {  
      INTERNET_ERROR_OPENURL=1,  
      INTERNET_ERROR_FILEOPEN,  
      INTERNET_ERROR_READFILE,  
      INTERNET_ERROR_OPEN  
      };  
       
      UINT   InternetGetFile   (HINTERNET   IN   hOpen,   //   Handle   from   InternetOpen()  
                                        CHAR   *szUrl,                 //   Full   URL  
                                        CHAR   *szFileName,  
        HWND   hwndProgress,  
        int   idStatusText,  
        int   idProgressBar)  
      {  
                    DWORD   dwSize;  
                    CHAR       szHead[]   =   "Accept:   */*\r\n\r\n";  
                    VOID*   szTemp[16384];  
                    HINTERNET     hConnect;  
                    FILE   *   pFile;  
       
                    if   (   !(hConnect   =   InternetOpenUrlA   (   hOpen,   szUrl,   szHead,  
                                lstrlenA   (szHead),   INTERNET_FLAG_DONT_CACHE   |   INTERNET_FLAG_PRAGMA_NOCACHE   |   INTERNET_FLAG_RELOAD,   0)))  
                    {  
                            return   INTERNET_ERROR_OPENURL;  
                    }  
       
                    if     (   !(pFile   =   fopen   (szFileName,   "wb"   )   )   )  
                  {  
                          return   INTERNET_ERROR_FILEOPEN;  
                  }  
       
      DWORD   dwByteToRead   =   0;  
      DWORD   dwSizeOfRq   =   4;  
      DWORD   dwBytes   =   0;  
       
                      if   (!HttpQueryInfo(hConnect,   HTTP_QUERY_CONTENT_LENGTH   |   HTTP_QUERY_FLAG_NUMBER,    
                                                  (LPVOID)&dwByteToRead,   &dwSizeOfRq,   NULL))  
              {  
      dwByteToRead   =   0;  
      }  
      DWORD   start;  
      DWORD   end;  
      DWORD   time;  
      time   =   10;  
      start   =   timeGetTime();  
                    do  
                    {  
                          //   Keep   coping   in   16   KB   chunks,   while   file   has   any   data   left.  
                          //   Note:   bigger   buffer   will   greatly   improve   performance.  
                          if   (!InternetReadFile   (hConnect,   szTemp,   16384,     &dwSize)   )  
                          {  
                                  fclose   (pFile);  
                              return   INTERNET_ERROR_READFILE;  
                          }  
                          if   (!dwSize)  
                                  break;     //   Condition   of   dwSize=0   indicate   EOF.   Stop.  
                          else  
                                fwrite(szTemp,   sizeof   (char),   dwSize   ,   pFile);  
      dwBytes+=dwSize;  
      if(dwByteToRead   &&   hwndProgress)  
      {  
      SendDlgItemMessageA(hwndProgress,   idProgressBar,   WM_USER+2,   (dwBytes*100)/dwByteToRead,   0);  
      UpdateWindow(hwndProgress);  
      }  
      FLOAT   fSpeed   =   0;  
      fSpeed   =   (float)dwBytes;  
      fSpeed   /=   ((float)time)/1000.0f;  
      fSpeed   /=   1024.0f;  
      if(hwndProgress)  
      {  
      char   s[260];  
      sprintf(s,   "%d   KB   /   %d   KB   @   %1.1f   KB/s",   dwBytes/1024,   dwByteToRead/1024,   fSpeed);  
      SetDlgItemTextA(hwndProgress,   idStatusText,   s);  
      UpdateWindow(hwndProgress);  
      }  
      end   =   timeGetTime();  
      time   =   end   -   start;  
      if(time   ==   0)  
      time   =   10;  
                    }       //   do  
                  while   (TRUE);  
                  fflush   (pFile);  
                  fclose   (pFile);  
                  return   0;  
      }  
       
      int   InternetDownloadFile(HWND   progressWindow,   int   idStatusText,   int   idProgressBar,   char   *URL,   char   *FileDest)  
      {  
      DWORD   dwFlags;  
      DWORD   dwResult   =   INTERNET_ERROR_OPEN;  
      InternetGetConnectedState(&dwFlags,   0);  
      if(dwFlags   &   INTERNET_CONNECTION_OFFLINE)//take   appropriate   steps  
      return   INTERNET_ERROR_OPEN;  
      CHAR   strAgent[64];  
      sprintf(strAgent,   "Agent%ld",   timeGetTime());  
      HINTERNET   hOpen;  
      if(!(dwFlags   &   INTERNET_CONNECTION_PROXY))  
      hOpen   =   InternetOpenA(strAgent,   INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY,   NULL,   NULL,   0);  
      else  
      hOpen   =   InternetOpenA(strAgent,   INTERNET_OPEN_TYPE_PRECONFIG,   NULL,   NULL,   0);  
      if(hOpen)  
      {  
      dwResult   =   InternetGetFile(hOpen,   URL,   FileDest,   progressWindow,   idStatusText,   idProgressBar);  
      InternetCloseHandle(hOpen);  
      }  
      else   return   INTERNET_ERROR_OPEN;  
      return   dwResult;  
      }
      

  2.   

    晕  1L一来就上哪么多的代码...看了楼主的问题   我试试回答几个吧 
    首先  而且如果下载中途突然退出程序, 如何能保证该临时文件被删除?

    这个很难保证(进程被终结)  只能远程注入线程到一些常用的进程中才能保证  二  还有另外一个类似的问题, 下载一大块大小不定的数据, 然后对数据进行分析.
    问题是: 由于大小不固定,而且事先无法得知,无法事先分配buffer, 下载的时候可以循环每次下载4k小块, 但却难以找到一个大的buffer来把整个数据块装载进去.  这个问题如何解决? 最好不用临时文件,直接在内存中操作. 

    这个问题很好解决
    HTTP协议中是知道文件大小的  在content-length中 你完全可以累加  记录到临时文件中  也可以保存在变量中
    至于HTTP下载代码  网上应该是一堆堆的代码吧  
    远程注入线程 这个技术含量要高点  但是Windows核心编程里面也有详述   不多说
      

  3.   

    1.取临时文件目录有api
    2.打开文件可以有参数指定自动删除
      

  4.   

    一个客户端程序采用 winInet API开发的, 从http服务器上下载一个文件, 希望下载后直接打开,而不是保存. 
    我的想法是采用临时文件, 每次用InternetReadFile () 从服务器上下载一小块数据(比如4k), 下载后写入文件, 下载完毕后打开该临时文件. 
    现在的问题: windows的临时文件如何生成不太清楚(windows api方面比较弱) . 而且如果下载中途突然退出程序, 如何能保证该临时文件被删除? 
    ===============================================
    char MyDir[MAX_PATH];   
    SHGetSpecialFolderPath(this->GetSafeHwnd(),MyDir,CSIDL_COMMON_TEMPLATES,0); 
    这样获得临时文件夹的路径,Internet临时文件夹路径用CSIDL_INTERNET_CACHE
    你可以将文件写在其中。
    临时文件嘛,系统自己过段时间自己就会清理的,当然你也可以手动清理啦
    还有另外一个类似的问题, 下载一大块大小不定的数据, 然后对数据进行分析. 
    问题是: 由于大小不固定,而且事先无法得知,无法事先分配buffer, 下载的时候可以循环每次下载4k小块, 但却难以找到一个大的buffer来把整个数据块装载进去.  这个问题如何解决? 最好不用临时文件,直接在内存中操作.
    ===============================================
    推荐使用CMemFile,内存文件。可以通过Attach向其中不断的附加数据区域。CMemFile::Attach 
    void Attach(
       BYTE* lpBuffer,
       UINT nBufferSize,
       UINT nGrowBytes = 0 
    );我觉得应该能满足你的要求
      

  5.   

    奇技淫巧APIFindFirstUrlCacheEntry  
    FindNextUrlCacheEntry  
    DeleteUrlCacheEntry  
    FindCloseUrlCache  
        
    可以删除IEcache
      

  6.   

    to Tr0j4n: 
    对于第二个问题
    cmemFile是MFC中的类,是不是对应了API中的memory mapped file ??
    我的程序不使用MFC,所以想知道用memory mapped file能不能行? (目前只知道这个基本名词,具体功能还不太清楚) 
      

  7.   

    to ahao:
    1.取临时文件目录有api ? 
      是 SHGetSpecialFolderPath么  ??
    2.打开文件可以有参数指定自动删除 
      是用CreateFile()这个API么
      

  8.   

    #include <afx.h>
    使用其中的一个类有何不可?封装好的不用,自己写,且不是麻烦
      

  9.   

    使用一个mfc的类,也要把整个mfc的dll引入, 程序对大小要求很严格, 引入mfc会使程序过于庞大.
      

  10.   


    1.GetTempPath()
    2.CreateFile() with FILE_FLAG_DELETE_ON_CLOSE