以下是可以运行的从Internet下载文件的源代码
对新手还是有点用的,算是我抛出的砖吧
本人刚接触这方面内容,所知不多,经验也很有限,
对如何优化这样的代码还不清楚,但任务紧迫
只好来这里"引玉"了
在StdAfx.h中添加了
如下代码#include <wininet.h>enum
{
INTERNET_ERROR_OPENURL = 1,
INTERNET_ERROR_FILEOPEN,
INTERNET_ERROR_READFILE,
INTERNET_ERROR_OPEN
};利用WinInet的“Internet文件下载”的函数源代码如下
其中参数szUrl指Internet文件的URL, szPath指文件在本地的保存路径和名称UINT CFileDownDlg::DownFile(CString szUrl, CString szPath)
{
DWORD dwFlags;
InternetGetConnectedState(&dwFlags, 0);
// if (dwFlags & INTERNET_CONNECTION_OFFLINE)  // 问题一:  这里注释掉了,因为不注释掉编译出错,说INTERNET_CONNECTION_OFFLINE
                                                    // 没有定义,查MSDN中InternetGetConnectedState函数可知在wininet.h
                                                    // 中已经包含了INTERNET_CONNECTION_OFFLINE的定义,为什么,怎么解决?
                                                    // 这段被注释掉的代码很有必要吗?
// {
// return INTERNET_ERROR_OPEN;
// }

HINTERNET hOpen;
CHAR szAgent[] = "test";  // 问题二:  查了MSDN也没发现这个参数具体有什么用,反正随便用了个test也行
if (!(dwFlags & INTERNET_CONNECTION_PROXY))
{
hOpen = InternetOpen(szAgent, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0);
}
else
{
hOpen = InternetOpen(szAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
} DWORD dwSize;
CHAR szHead[] = "Accept: */*\r\n\r\n";
VOID *szTemp[16384];
HINTERNET hConnect;
FILE *pFile;
if (hOpen)
{
if (!(hConnect = InternetOpenUrl(hOpen, szUrl, szHead, lstrlen(szHead), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0)))
{
return INTERNET_ERROR_OPENURL;
}
if (!(pFile = fopen(szPath, "wb")))  // 问题三:  比如"F:\test"不存在,则当szPath为"F:\test\1.jpg"时
                                                     // 不起作用,只有原来"F:\test"存在
                                                     // 才会新建一个文件,要是原来没有相应路径,不会新建一个路径加文件,
                                                     // 以前我用fopen似乎是可以创建整个路径加文件的
{
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;
}

while (TRUE)
                {
if (!InternetReadFile(hConnect, szTemp, 16384, &dwSize))
{
fclose(pFile);
return INTERNET_ERROR_READFILE;
}
if (!dwSize)
break;
else
fwrite(szTemp, sizeof(char), dwSize, pFile);
dwBytes += dwSize;
}
fflush(pFile);
fclose(pFile);
return 0;
}
else
{
return INTERNET_ERROR_OPEN;
}
}虽然这段代码可以执行,但还有些问题问题四:  执行下载时程序常陷入没有响应,下载完了才好,但下载效率不高,在FlashGet显示有20~30k的网速下一个40K的jpg文件要20秒以上,最
慢好几分钟,请问问题出在哪里?这段代码应该如何优化?
问题五:  是否WinInet本身效率不是很高?如果不用WinInet该怎么下载文件?
问题六:  是否用多线程的方式下载效率可能有很大提高?这段代码主要用来下载图片文件,文件不大,多线程下载是用不同线程下载不同文件好
还是用不同线程下载同一文件好?
问题七:  16384(2的14次方)这样的常数能否作为一个变量在程序运行时手工输入,按照C语言规则似乎不能这样,如何解决?
请按各问题回答,如下,多少说一点吧,看,大伙都等着呢:)问题一:
问题二:
问题三:
问题四:
问题五:
问题六:
问题七:
您的其他高见:

解决方案 »

  1.   

    我以前写的很简单,^_^:
    CString GetFile(const char *url, const char *filename)
    {
         #define HTTPBUFLEN    512 // Size of HTTP Buffer...
         char httpbuff[HTTPBUFLEN];
         TCHAR   szCause[255];
         CString Cause;
         Cause.Format("YES");
     
         TRY
         {
              CInternetSession mysession;
              CStdioFile *remotefile =           mysession.OpenURL(url,1,INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_RELOAD);
              CFile myfile(filename, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
              while (int numbytes = remotefile->Read(httpbuff, HTTPBUFLEN))
                   myfile.Write(httpbuff, numbytes);
         }
     
         CATCH_ALL(error)
         {
              error->GetErrorMessage(szCause,254,NULL);
              Cause.Format("%s",szCause);
         }
         END_CATCH_ALL;
     
         return (Cause);
    }
      

  2.   

    我写的跟gdy119的差不多,为什么要那么复杂
      

  3.   

    我更习惯用SOCKET来做,也用不了多少代码的说。
    对你给的那些API没用过,不太熟悉。
      

  4.   

    问题四:程序和web服务器链接时有个链接期 你关查 一下 FalshGet  就会发现 他下载一个程序有一部分时间是在和服务器 握手 链接~~~这个是没有什么办法解决的~~问题五:WinInet 只是提供给你了一些相关函数 方法 如果你不用 自己完全可以用 winsock 自己些个 “WinInet” 呵呵~~不过 要自己解析 呵呵~~相信你完全搞成 你就是个高手了:)问题六: “ 是否用多线程的方式下载效率可能有很大提高? ”这个不能万全肯定的说 但是一般 应该 效率会高一点~
    “这段代码主要用来下载图片文件,文件不大,多线程下载是用不同线程下载不同文件好”
    呵呵 对于小的文件 建议 多线程下载是不同文件 因为 问题四说了 和服务器建立链接是需要浪费时间的:)问题七:
    BOOL InternetReadFile(
        IN HINTERNET hFile,
        IN LPVOID lpBuffer,
        IN DWORD dwNumberOfBytesToRead,
        OUT LPDWORD lpNumberOfBytesRead
    );
    因该是可以当参数 传入的~#define 下问题二:
    lpszAgent 
    Address of a string that contains the name of the application or entity calling the Internet functions (for example, Microsoft Internet Explorer). This name is used as the user agent in the HTTP protocol. 
    这个值好想是告诉服务器 你的程序的name:)可以随便~~
    问题三:  何必强求 你要的是Like FlashGet 先 Like 在优化:)
    呵呵~~~希望对你有帮助:)
    嘻嘻~~~~
      

  5.   

    呵呵.好多人犯的错误是:不按接收的长度保存接收到的信息.明明nLen=recv(),保存的时候却直写把整个接收缓冲区当作接收到的内容了.