一个客户端程序采用 winInet API开发的, 从http服务器上下载一个文件, 希望下载后直接打开,而不是保存.
我的想法是采用临时文件, 每次用InternetReadFile () 从服务器上下载一小块数据(比如4k), 下载后写入文件, 下载完毕后打开该临时文件.
现在的问题: windows的临时文件如何生成不太清楚(windows api方面比较弱) . 而且如果下载中途突然退出程序, 如何能保证该临时文件被删除?还有另外一个类似的问题, 下载一大块大小不定的数据, 然后对数据进行分析.
问题是: 由于大小不固定,而且事先无法得知,无法事先分配buffer, 下载的时候可以循环每次下载4k小块, 但却难以找到一个大的buffer来把整个数据块装载进去. 这个问题如何解决? 最好不用临时文件,直接在内存中操作.大家可以给出好的点子和建议,最好有代码,谢谢了
我的想法是采用临时文件, 每次用InternetReadFile () 从服务器上下载一小块数据(比如4k), 下载后写入文件, 下载完毕后打开该临时文件.
现在的问题: windows的临时文件如何生成不太清楚(windows api方面比较弱) . 而且如果下载中途突然退出程序, 如何能保证该临时文件被删除?还有另外一个类似的问题, 下载一大块大小不定的数据, 然后对数据进行分析.
问题是: 由于大小不固定,而且事先无法得知,无法事先分配buffer, 下载的时候可以循环每次下载4k小块, 但却难以找到一个大的buffer来把整个数据块装载进去. 这个问题如何解决? 最好不用临时文件,直接在内存中操作.大家可以给出好的点子和建议,最好有代码,谢谢了
#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;
}
首先 而且如果下载中途突然退出程序, 如何能保证该临时文件被删除?
这个很难保证(进程被终结) 只能远程注入线程到一些常用的进程中才能保证 二 还有另外一个类似的问题, 下载一大块大小不定的数据, 然后对数据进行分析.
问题是: 由于大小不固定,而且事先无法得知,无法事先分配buffer, 下载的时候可以循环每次下载4k小块, 但却难以找到一个大的buffer来把整个数据块装载进去. 这个问题如何解决? 最好不用临时文件,直接在内存中操作.
这个问题很好解决
HTTP协议中是知道文件大小的 在content-length中 你完全可以累加 记录到临时文件中 也可以保存在变量中
至于HTTP下载代码 网上应该是一堆堆的代码吧
远程注入线程 这个技术含量要高点 但是Windows核心编程里面也有详述 不多说
2.打开文件可以有参数指定自动删除
我的想法是采用临时文件, 每次用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
);我觉得应该能满足你的要求
FindNextUrlCacheEntry
DeleteUrlCacheEntry
FindCloseUrlCache
可以删除IEcache
对于第二个问题
cmemFile是MFC中的类,是不是对应了API中的memory mapped file ??
我的程序不使用MFC,所以想知道用memory mapped file能不能行? (目前只知道这个基本名词,具体功能还不太清楚)
1.取临时文件目录有api ?
是 SHGetSpecialFolderPath么 ??
2.打开文件可以有参数指定自动删除
是用CreateFile()这个API么
使用其中的一个类有何不可?封装好的不用,自己写,且不是麻烦
1.GetTempPath()
2.CreateFile() with FILE_FLAG_DELETE_ON_CLOSE