IE缓存管理研究

引言

关于IE缓存管理方面的资料非常少,网上虽然有部分文章介绍,也有工具下载(如搜索缓存或清除缓存等),但都不够全面和深入。

另外,IE缓存管理主要依赖几个index.dat文件和wininet库,而MSDNwininet库的帮助非常简单,而且没有示例代码。

网上能够找到的资料大部分都是对wininethttp协议处理接口方面的介绍,对于缓存处理部分介绍的很少,加上这部分接口定义得有点晦涩,所以让人觉得有点困绕。

本文结合自己的项目经验,对IE的缓存机制,特别是wininet库中缓存管理的接口使用,提出全面深入的说明。

弄懂了wininet缓存管理接口,以后写缓存监控、缓存搜索和缓存清理等工具就非常简单了。

 

2.       术语定义

无。

 

 

 

 

 

3.       IE缓存文件

3.1.       IE缓存分类

IE缓存主要分为3大类:cookie、临时文件(包括未过期的资源和脱机文件)、历史记录。

3类缓存分别都有一个索引文件,文件名为index.dat

存放路径如下(以我的电脑为例):

缓存内容索引:C:/Documents and Settings/liyafeng/Local Settings/Temporary Internet Files/Content.IE5/index.dat

缓存cookie索引:C:/Documents and Settings/liyafeng/Cookies/index.dat

历史记录索引:C:/Documents and Settings/liyafeng/Local Settings/History/History.IE5/index.dat

3index.dat文件格式被加密处理过,微软没有公开也不打算公开文件格式,这种做法被很多人指责,但是微软依然我行我素。

通过IEinternet选项清除缓存时不能删除index.dat文件,但是在磁盘清除临时文件时会删除这3index.dat文件。

通过IE清除缓存的方法如下:

 

目前访问这些索引文件的唯一方法是通过wininet库的相关接口,这也是本文重点介绍的地方。

注意:缓存的临时文件被文件系统做了特殊处理,只能通过完整目录路径访问,否则无法看到,即使你显示所有文件和系统文件。

 

 

 

 

3.2.       IE缓存管理的流程

流程如下:

1、  启动IE

2、  如果不存在就创建缓存内容索引:C:/Documents and Settings/liyafeng/Local Settings/Temporary Internet Files/Content.IE5/index.dat

3、  如果不存在就创建cookie索引:C:/Documents and Settings/liyafeng/Cookies/index.dat

4、  如果不存在历史记录就创建历史索引:C:/Documents and Settings/liyafeng/Local Settings/History/History.IE5/index.dat

5、  调用InternetOpen初始化一个IE应用。

6、  设置回调函数,通过InternetSetStatusCallback

7、  枚举cookie列表。

8、  枚举临时文件列表。

9、  枚举历史记录列表。

10、              枚举当前用户的访问列表。

11、              查询当前访问的url是否被缓存。

12、              如果被缓存,则从缓存中读取相应的信息,包括最后修改时间、最后访问时间和过期时间。

13、      发送http请求。

14、      http服务器会检查访问的资源是否过期,如果未过期,则会返回“304 Not Modified”。

15、      根据缓存的索引信息,从本地临时文件中提取内容。

16、      如果第11步中没有被缓存,则直接从http服务器下载资源。

 

 

4.       Wininet库的缓存管理接口

4.1.       简介

Wininet库内置有简单却灵活的缓冲支持。从网络接收到的任何数据都会缓存到硬盘中,然后在后续请求中被获取。应用程序可以控制每个请求的缓存。对于来自服务器的HTTP请求,大多数收到的头部也被缓存。当从缓存中为HTTP请求获取响应时,也会把缓存的头部数据返回给调用者。这使得数据下载对于用户是透明的,无论数据是来自缓存还是来自网络。

    接口分为枚举缓存、创建缓存、查询缓存和删除缓存,以及对缓存组的操作。

 

4.2.       枚举缓存

FindFirstUrlCacheEntry  开始对缓存的枚举

FindFirstUrlCacheEntryEx    开始对缓存的过滤型枚举

FindNextUrlCacheEntry   返回缓存中的下一个条目

FindNextUrlCacheEntryEx 在过滤型枚举中返回下一个缓存条目

FindCloseUrlCache   关闭指定的枚举句柄

FindFirstUrlCacheEntryFindNextUrlCacheEntry函数可枚举缓存中存储的信息。FindFirstUrlCacheEntry使用传入的搜索模式、缓冲区及其尺寸来创建枚举句柄,并返回第一个缓存条目。FindNextUrlCacheEntry使用FindFirstUrlCacheEntry创建的句柄,一个缓冲区及其尺寸,返回下一个缓存条目。

这两个函数都在缓冲区中存入一个INTERNET_CACHE_ENTRY_INFO条目。对于各个条目,结构体的大小是不同的。如果传入的缓冲区尺寸不够大,则函数调用失败,GetLastError返回ERROR_INSUFFICIENT_BUFFER。此时缓冲区尺寸参数值会指示缓存条目所需的缓冲区尺寸,应该分配一个这么大的缓冲区,然后重新调用函数。

INTERNET_CACHE_ENTRY_INFO结构体包含结构体尺寸、缓存信息的URL、本地文件名、缓存条目类型、使用计数、命中率、尺寸、最后修改时间、失效时间、最后访问时间、最后同步时间、头部信息、头部信息尺寸和文件扩展名信息。

FindFirstUrlCacheEntry函数要求传入搜索模式和用于存储INTERNET_CACHE_ENTRY_INFO结构体的缓冲区及其尺寸。当前仅实现了默认搜索模式,它返回所有缓存条目。

缓存枚举完成后,应该用FindCloseUrlCache关闭缓存枚举句柄。

注意:FindNextUrlCacheEntry返回FALSE时,有两种可能。一种是INTERNET_CACHE_ENTRY_INFO条目分配的缓冲区不够,另一种可能是枚举结束。

关于缓存区不够如何处理,还有嵌入式指针问题,在后面查询缓存中会给出示例代码。

 

4.3.       查询缓存条目信息

GetUrlCacheEntryInfo        获取某缓存条目的信息

GetUrlCacheEntryInfoEx     转换任何会被HttpSendRequest应用于离线模式的缓存重定向,然后搜索指定的URL

GetUrlCacheEntryInfo函数获取指定URLINTERNET_CACHE_ENTRY_INFO结构体。结构体包含结构体尺寸、缓存信息的URL、本地文件名、缓存条目类型、使用计数、命中率、尺寸、最后修改时间、失效时间、最后访问时间、最后同步时间、头部信息、头部信息尺寸和文件扩展名信息。

GetUrlCacheEntryInfo接受一个URL、一个用于保存INTERNET_CACHE_ENTRY_INFO结构体的缓冲区及其尺寸。如果找到了给定的URL,其信息会复制到缓冲区中。否则,函数调用失败,GetLastError返回ERROR_FILE_NOT_FOUND。如果缓冲区大小不足以保存缓存条目信息,则函数调用失败,GetLastError返回ERROR_INSUFFICIENT_BUFFER。此时缓冲区尺寸参数会指示所需要的缓冲区尺寸。

GetUrlCacheEntry不会做URL解析,所以对于含有锚定(#)URL,即使请求的资源在缓存中,函数也会找不到。比如说,如果传入 http://example.com/example.htm#sample,即使它在缓存中,函数也会返回ERROR_FILE_NOT_FOUND

typedef struct _INTERNET_CACHE_ENTRY_INFOA {

    DWORD dwStructSize;         // version of cache system.

    LPSTR   lpszSourceUrlName;    // embedded pointer to the URL name string.

    LPSTR   lpszLocalFileName;  // embedded pointer to the local file name.

    DWORD CacheEntryType;       // cache type bit mask.

    DWORD dwUseCount;           // current users count of the cache entry.

    DWORD dwHitRate;            // num of times the cache entry was retrieved.

    DWORD dwSizeLow;            // low DWORD of the file size.

    DWORD dwSizeHigh;           // high DWORD of the file size.

    FILETIME LastModifiedTime;  // last modified time of the file in GMT format.

    FILETIME ExpireTime;        // expire time of the file in GMT format

    FILETIME LastAccessTime;    // last accessed time in GMT format

    FILETIME LastSyncTime;      // last time the URL was synchronized

                                // with the source

    LPSTR   lpHeaderInfo;        // embedded pointer to the header info.

    DWORD dwHeaderInfoSize;     // size of the above header.

    LPSTR   lpszFileExtension;  // File extension used to retrive the urldata as a file.

        union {                     // Exemption delta from last access time.

                DWORD dwReserved;

                DWORD dwExemptDelta;

    };                          // Exemption delta from last access

} INTERNET_CACHE_ENTRY_INFOA, * LPINTERNET_CACHE_ENTRY_INFOA;

注意:embedded pointer即嵌入式指针,是一个比较晦涩的点,真实意义是在结构体后分配一块连续内存,然后让这个指针指向它,就好象是嵌入在结构体内,因此得名。

不知道是否解释清楚,后面以示例代码来说明,呵呵。

示例代码:

INTERNET_CACHE_ENTRY_INFOA *lpCacheEntryInfo = new INTERNET_CACHE_ENTRY_INFOA;

DWORD cbCacheEntryInfo = sizeof(INTERNET_CACHE_ENTRY_INFOA);

BOOL fOk = GetUrlCacheEntryInfoA(lpszUrl,lpCacheEntryInfo,&cbCacheEntryInfo);

if( !fOk && cbCacheEntryInfo > sizeof(INTERNET_CACHE_ENTRY_INFOA) )

{

    lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFOA) new char[cbCacheEntryInfo];//强制转换,保证指针可以指向结构体内部。

    fOk = GetUrlCacheEntryInfoA(lpszUrl,lpCacheEntryInfo,&cbCacheEntryInfo);

    PR_DEBUG("do again:fOk:%d,cbCacheEntryInfo:%d",fOk,cbCacheEntryInfo);

}

 

4.4.       创建缓存条目

 CreateUrlCacheEntry 分配请求的缓存存储器,创建本地文件名用于保存对应源名称的缓存条目

CommitUrlCacheEntry 缓存存储器中某特定文件中的数据,将它与给定的URL关联起来

使用CreateUrlCacheEntryCommitUrlCacheEntry可以创建缓存条目。

CreateUrlCacheEntry接受URL、预期的文件尺寸和文件扩展名,创建用于保存相应缓存条目的本地文件名。可以使用这个文件名向本地文件中写入数据。数据写入完成后应该调用CommitUrlCacheEntry

CommitUrlCacheEntry接受URL、本地文件名、失效时间、最后修改时间、缓存条目类型、头部信息及其尺寸和文件扩展名,在缓存存储器中保存文件数据,并与给定的URL关联起来。

注意:CreateUrlCacheEntry只是在内存中创建缓存条目,必须调用CommitUrlCacheEntry才写入index.dat文件中。另外,CreateUrlCacheEntry会创建一个空的临时文件。CommitUrlCacheEntry会校验文件名与url的关系,这是IE防止用户把临时文件挪到其他地方的一种手段。

 

 

 

4.5.       删除缓存条目

DeleteUrlCacheEntry 如果缓存中存在与源名称相关的文件,删除它。

 DeleteUrlCacheEntry删除与给定URL相关的缓存文件。如果没有找到相应的缓存文件,则函数调用失败,GetLastError返回ERROR_FILE_NOT_FOUND。如果缓存文件当前被锁定或者正在使用中,则函数调用失败,GetLastError返回ERROR_ACCESS_DENIED。文件解锁后会被删除。

 

4.6.       获取缓存文件

RetrieveUrlCacheEntryFile 以文件的形式从缓存中获取一个缓存条目

UnlockUrlCacheEntryFile 解锁因为使用RetrieveUrlCacheEntryFile从缓存中获取其文件用于使用而被锁定的缓存条目。

对于要求某资源的文件名才能的启动的应用程序,可使用RetrieveUrlCacheEntryFileUnlockUrlCacheEntryFile函数。

不要求文件名的程序应该使用RetrieveUrlCacheEntryStreamReadUrlCacheEntryStreamUnlockUrlCacheEntryStream获取缓存信息。

RetrieveUrlCacheEntryFile接受一个URL和用于保存INTERNET_CACHE_ENTRY_INFO结构体的缓冲区及其尺寸,为调用者获取并锁定缓存文件。

使用完缓存文件后,应该调用UnlockUrlCacheEntryFile解锁文件。

注意:虽然你也可以直接使用readfile来读取缓存条目,但是此时对文件没有加锁,因此在读取的过程中可能会被修改或删除,因此推荐使用RetrieveUrlCacheEntryFile

使用方法:先调用RetrieveUrlCacheEntryFile获取条目信息并对文件加锁,条目信息中有缓存文件的本地文件名,然后调用readfile读取文件内容,读取完成后调用UnlockUrlCacheEntryFile解锁。

 

4.7.       获取缓存流

RetrieveUrlCacheEntryStream 提供最高效的、实现无关的访问缓存数据的方法。

ReadUrlCacheEntryStream RetrieveUrlCacheEntryStream打开的流中读取缓存数据。

RetrieveUrlCacheEntryStreamReadUrlCacheEntryStreamUnlockUrlCacheEntryStream用于获取缓存中的资源。

RetrieveUrlCacheEntryStream接受一个URL,一个用于存储INTERNET_CACHE_ENTRY_INFO结构体的缓冲区及其尺寸和一个表明是否可以进行随机读取的布尔值。如果找到了缓存文件,函数会创建到文件的句柄。函数不做URL解析,所以对于含有锚定(#)URL,即使资源在缓存中,它也找不到。比如说,如果传入 http://example.com/example.htm#sample,即使它在缓存中,函数也会返回ERROR_FILE_NOT_FOUND

ReadUrlCacheEntryStream要求传入RetrieveUrlCacheEntryStream创建的句柄、文件偏移量、缓冲区及其尺寸。如果缓冲区不足以容纳可用数据,函数调用会失败,GetLastError返回ERROR_INSUFFICIENT_BUFFER,缓冲区尺寸参数会被设置为下载资源所需缓冲区大小。

获取缓存文件后,应该调用UnlockUrlCacheEntryStream关闭RetrieveUrlCacheEntryStream创建的句柄。

注意:流操作主要针对不关心本地文件名的应用,所有读取和关闭流的操作都必须使用RetrieveUrlCacheEntryStream返回的句柄。

 

4.8.       缓存组操作

CreateUrlCacheGroup 生成一个缓存组标识

SetUrlCacheEntryGroup 向缓存组添加条目,或者从中删除条目

DeleteUrlCacheGroup 释放GROUPID以及缓存索引文件中任何与之相关的状态

要创建缓存组,必须调用CreateUrlCacheGroup为其生成一个GROUPID。使用SetUrlCacheEntryGroup函数,提供缓存条目的URLINTERNET_CACHE_GROUP_ADD标志就可以把条目加入到缓存组中。要从缓存组中删除条目,则传入条目的URL,使用INTERNET_CACHE_GROUP_REMOVE标志。

FindFirstUrlCacheEntryExFindNextUrlCacheEntryEx函数可以枚举指定缓存组中的条目。完成枚举后,应该用FindCloseUrlCache关闭枚举句柄。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章