C++实现IE缓存迭代器

来源:互联网 发布:四川旅游五天 知乎 编辑:程序博客网 时间:2024/05/17 09:03

1、迭代器的定义:

     提供一种方法,使之能够依序访问某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表述方式。

2、迭代器的设计动机

  一个聚合对象,应该提供一种方法来让别人可以访问它的元素,而又不需暴露它的内部结构。此外,针对不同的需要,可能要以不同的方式遍历这个容器。但即使可以预见到所需的那些遍历操作,你可能也不希望容器的接口中充斥着各种不同的遍历的操作。有时可能需要在同一个容器上同时进行多个遍历。

      迭代器模式的关键思想是将对列表的访问和遍历从容器对象中分离出来并放入一个迭代器(iterator)对象中。迭代器类定义了一个访问该容器的接口。迭代器对象负责跟踪当前的元素;即它知道哪些元素已经遍历过了。将遍历机制与列表对象分离使我们可以定义不同的迭代器来实现不同的遍历策略,而无需在容器接口中列举它们。

      一般一个迭代器类需要提供以下操作:

(1)    First():初始化迭代器,使当前元素指向列表的第一个元素。

(2)    Next():将当前元素指针向前推进一步,指向下一个元素。

(3)    CurrentItem():返回容器中的当前元素。

(4)    IsDone():检查是否已越过最后一个元素,也就是完成了本次遍历。

3、迭代器的适用性

(1)访问一个聚合对象的内容而无需暴露它的内部表示。

(2)支持对聚合对象的多种遍历

(3)为遍历不同的聚合结构提供一个统一的接口

4、空迭代器

     一个空迭代器(NullIterator)是一个退化的迭代器,它有助于处理边界条件,根据定义,空迭代器总是已经完成了遍历,即,它的IsDone操作总是返回true;

5、例子——IE缓存迭代器

        以下用C++实现一个迭代器类,用于遍历IE缓存空间。我们在访问网站或本地文件时,系统会把图片、动画、浏览记录等信息保存在Internet临时文件夹中,但这个文件夹是一个隐藏文件夹,不同于普通文件夹,Win32 API给用户提供了很多接口用于访问,修改这个文件夹里的内容。为了展示怎样怎样设计IE缓存迭代器,需要用到以下Win32 API。

5.1 需要用到的Win32 API

最低配置,头文件、库及动态链接库:

Minimum supported client

Windows 2000 Professional [desktop apps only]

Minimum supported server

Windows 2000 Server [desktop apps only]

Header

Wininet.h

Library

Wininet.lib

DLL

Wininet.dll

(1)IE缓存的入口点

HANDLE FindFirstUrlCacheEntry( _In_     LPCTSTR lpszUrlSearchPattern, _Out_    LPINTERNET_CACHE_ENTRY_INFO lpFirstCacheEntryInfo, _Inout_  LPDWORD lpcbCacheEntryInfo);

参数:

lpszUrlSearchPattern [in]:一个字符串指针,该字符串指定索引模式,该参数只能被设定为以下三个值:

     “cookie:”:列举出IE缓存的cookie;

     “visited:”:列表出缓存空间中的URL历史记录;

     NULL:列表出缓存空间中的所有内容

lpFirstCacheEntryInfo [out]:指向 INTERNET_CACHE_ENTRY_INFO 结构的指针

lpcbCacheEntryInfo [in,out]:指向DWORD变量的指针,用于指定lpcbCacheEntryInfo缓冲区的大小,以字节为单位。当函数返回时,该变量包含了该缓冲区的实际大小。

返回值:

返回一个被FindNextUrlCacheEntry访问随后的缓存空间所使用的句柄,如果该函数失败,则返回NULL。要想得到扩展错误信息,调用GetLastError函数获取。

(2) 获取IE缓存的下一个入口点

BOOL FindNextUrlCacheEntry( _In_     HANDLE hEnumHandle, _Out_    LPINTERNET_CACHE_ENTRY_INFO lpNextCacheEntryInfo, _Inout_  LPDWORD lpcbCacheEntryInfo);

参数:

hEnumHandle [in]:调用FindFirstUrlCacheEntry返回的句柄

lpNextCacheEntryInfo [out]:指向INTERNET_CACHE_ENTRY_INFO 结构的指针

lpcbCacheEntryInfo [in,out]:指向DWORD变量的指针,用于指定lpcbCacheEntryInfo缓冲区的大小,以字节为单位。当函数返回时,该变量包含了该缓冲区的实际大小。

返回值:

     如果成功则返回true,否则返回false.要想获取扩展错误信息,需要调用GetLastError,可能的错误值如下:

ERROR_INSUFFICIENT_BUFFER:lpcbCacheEntryInfo不足以提供lpNextCacheEntryInfo 指定的大小,函数返回时,lpcbCacheEntryInfo包含lpcbCacheEntryInfo指定的实际大小。

ERROR_NO_MORE_ITEMS:列举完成。

(3)关闭IE缓存句柄

BOOL FindCloseUrlCache( _In_  HANDLE hEnumHandle);

参数:

hEnumHandle [in]:调用FindFirstUrlCacheEntry返回的句柄

返回值:

如果成功则返回true,否则返回false.要想获取扩展错误信息,需要调用GetLastError。

(4)IE缓存结构体,包含IE缓存的信息

typedefstruct_INTERNET_CACHE_ENTRY_INFO { DWORD   dwStructSize; LPTSTR  lpszSourceUrlName; LPTSTR  lpszLocalFileName; DWORD   CacheEntryType; DWORD   dwUseCount; DWORD   dwHitRate; DWORD   dwSizeLow; DWORD   dwSizeHigh; FILETIME LastModifiedTime; FILETIME ExpireTime; FILETIME LastAccessTime; FILETIME LastSyncTime; LPTSTR  lpHeaderInfo; DWORD   dwHeaderInfoSize; LPTSTR  lpszFileExtension; union {   DWORD dwReserved;   DWORD dwExemptDelta; };}INTERNET_CACHE_ENTRY_INFO,*LPINTERNET_CACHE_ENTRY_INFO;

由于该结构体成员比较多,在此不一一解译,请参考MSDNhttp://msdn.microsoft.com/zh-cn/library/windows/desktop/aa385134(v=vs.85).aspx

5.2、CacheIterator类

(1)成员变量

     用以上三个API中可以得知,FindFirstUrlCacheEntry返回的句柄hEnumHandle,指向INTERNET_CACHE_ENTRY_INFO 结构的指针lpCacheEntryInfo,还有INTERNET_CACHE_ENTRY_INFO 的实际大小都是要经常用到的变量,因此把它们作为CacheIterator的成员变量,如下:

HANDLE m_hCacheEntry;

LPINTERNET_CACHE_ENTRY_INFO m_lpCacheEntryInfo;

DWORD m_dwNeedBufSize;

(2)成员函数

     从迭代器模式需要提供的四个操作来看,First和Next操作和FindFirstUrlCacheEntry与FindNextUrlCacheEntry是一一对应的;CurrentItem用于返回m_lpCacheEntryInfo所指向的IE缓存结构体INTERNET_CACHE_ENTRY_INFO;为了处理边界条件,同样需要IsDone操作,该操作只需判断m_lpCacheEntryInfo是否为NULL.

     为了给出具体的代码,在此选择C++语言进行描述。从面向对象来看,我们可以在构造函数中进行初始化,即实现First操作;由于C++语言具有操作符重载机制,我们可以在前置operator++(),和后置operator++(int)中实现Next操作;同样由于操作符重载,我们可以在operator*()中实现CurrentItem操作,该成员函数用于返回m_lpCacheEntryInfo指向INTERNET_CACHE_ENTRY_INFO结构体的一个引用;最后一个问题是怎样实现IsDone操作呢?即该操作用于处理边界条件,判断遍历是否结束。在此,如果我们在构造的时候能够构造一个空迭代器,即当迭代器为空的时候,表示IsDone,遍历完成。空迭代器很简单,我们只需要将其m_lpCacheEntryInfo设为NULL即可。由于我们要进行比较操作,所以需要重载operator==和operator!=操作符。如下,得到了以下成员函数:

explicit CacheIterator();

explicit CacheIterator(LPCSTR accessMethod);

booloperator==(constCacheIterator& rhs);

booloperator!=(constCacheIterator& rhs);

INTERNET_CACHE_ENTRY_INFO& operator*();

CacheIterator& operator++();

CacheIterator operator++(int );

(3)主要成员函数的实现

构造函数:

     从FindFirstUrlCacheEntry的第一个参数lpszUrlSearchPattern,我们也需要提供两样的接口给用户指定访问模式。在无参构造函数中,我们指定lpszUrlSearchPattern为0,即可以访问IE缓存的全部内容。在CacheIterator(LPCSTRaccessMethod)中可以给accessMethod指定访问模式,当accessMethod为空时,我们设定为空迭代器。构造函数如下:

CacheIterator::CacheIterator(){     Init(0);} CacheIterator::CacheIterator(LPCSTR accessMethod)     :m_hCacheEntry(0),m_lpCacheEntryInfo(0), m_dwNeedBufSize(0){     if(accessMethod != 0)          Init(accessMethod);} void CacheIterator::Init(LPCSTR accessMethod){     FindFirstUrlCacheEntry(accessMethod,0, &m_dwNeedBufSize);     m_lpCacheEntryInfo = reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>          (new char[m_dwNeedBufSize]);     m_hCacheEntry = FindFirstUrlCacheEntry(accessMethod, m_lpCacheEntryInfo,&m_dwNeedBufSize);}

前置Operator++

CacheIterator& CacheIterator::operator++(){     if(!FindNextUrlCacheEntry(m_hCacheEntry, m_lpCacheEntryInfo,&m_dwNeedBufSize))     {          delete[] m_lpCacheEntryInfo;          switch(GetLastError())          {          case ERROR_NO_MORE_ITEMS:                FindCloseUrlCache(m_hCacheEntry);                m_hCacheEntry= 0;                break;          case ERROR_INSUFFICIENT_BUFFER:                m_lpCacheEntryInfo = reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>                     (new char[m_dwNeedBufSize]);                if(!FindNextUrlCacheEntry(m_hCacheEntry, m_lpCacheEntryInfo, &m_dwNeedBufSize))                {                     delete[] m_lpCacheEntryInfo;                     FindCloseUrlCache(m_hCacheEntry);                     m_lpCacheEntryInfo = 0;                }                break;          default:                FindCloseUrlCache(m_hCacheEntry);                m_lpCacheEntryInfo = 0;                break;          }     }     return *this;}

6、完整代码:

///cacheiterator.h#ifndef__CACHEITERATOR_H__#define__CACHEITERATOR_H__ #include"windows.h"#include"wininet.h"#pragmacomment(lib,"wininet.lib") class CacheIterator{public:     explicit CacheIterator();     explicit CacheIterator(LPCSTRaccessMethod);     bool operator==(constCacheIterator& rhs);     bool operator!=(constCacheIterator& rhs);     INTERNET_CACHE_ENTRY_INFO& operator*();     CacheIterator& operator++();     CacheIterator operator++(int );private:     void Init(LPCSTR accessMethod);private:     HANDLE m_hCacheEntry;     LPINTERNET_CACHE_ENTRY_INFO m_lpCacheEntryInfo;     DWORD m_dwNeedBufSize;};#endif ///cacheiterator.cpp#include"cacheiterator.h" CacheIterator::CacheIterator(){     Init(0);} CacheIterator::CacheIterator(LPCSTR accessMethod)     :m_hCacheEntry(0),m_lpCacheEntryInfo(0),m_dwNeedBufSize(0){     if(accessMethod != 0)          Init(accessMethod);} void CacheIterator::Init(LPCSTR accessMethod){     FindFirstUrlCacheEntry(accessMethod,0,&m_dwNeedBufSize);     m_lpCacheEntryInfo = reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>          (new char[m_dwNeedBufSize]);     m_hCacheEntry = FindFirstUrlCacheEntry(accessMethod, m_lpCacheEntryInfo,&m_dwNeedBufSize);} bool CacheIterator::operator==(const CacheIterator& rhs){     return m_hCacheEntry == rhs.m_hCacheEntry;} bool CacheIterator::operator!=(const CacheIterator& rhs){     return !(*this == rhs);} INTERNET_CACHE_ENTRY_INFO& CacheIterator::operator*(){     return *m_lpCacheEntryInfo;} CacheIterator& CacheIterator::operator++(){     if(!FindNextUrlCacheEntry(m_hCacheEntry,m_lpCacheEntryInfo,&m_dwNeedBufSize))     {          delete[] m_lpCacheEntryInfo;          switch(GetLastError())          {          case ERROR_NO_MORE_ITEMS:                FindCloseUrlCache(m_hCacheEntry);                m_hCacheEntry = 0;                break;          case ERROR_INSUFFICIENT_BUFFER:                m_lpCacheEntryInfo = reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>                     (new char[m_dwNeedBufSize]);                if(!FindNextUrlCacheEntry(m_hCacheEntry,m_lpCacheEntryInfo, &m_dwNeedBufSize))                {                     delete[] m_lpCacheEntryInfo;                     FindCloseUrlCache(m_hCacheEntry);                     m_lpCacheEntryInfo = 0;                }                break;          default:                FindCloseUrlCache(m_hCacheEntry);                m_lpCacheEntryInfo = 0;                break;          }     }     return *this;} CacheIterator CacheIterator::operator++(int){     CacheIterator preCacheIter = *this;     ++*this;     return preCacheIter;}

7、测试——统计IE缓存的cookie项总数

int main(){         CacheIterator beg("cookie:"),end(0);         int cnt = 0;         for ( ; beg != end; ++beg)         {                  //cout<<(*beg).lpszLocalFileName<<endl;                 ++cnt;         }         cout<<"sum of cookies ="<<cnt<<endl;         return 0;}

8、更多参考资料

[1] http://msdn.microsoft.com/en-us/magazine/cc301955.aspx

[2] http://www.cnblogs.com/yelaiju/archive/2010/10/01/1839860.html

[3]Erich Gamma,Richard Helm等著.设计模式[M],北京:机械工业出版社,2012.6

[4]侯捷著.STL源码剖析[M],湖北:华中科技大学出版社,2011.12

 

注:欢迎各个网友指出错误,一起探讨,大家共同进步!

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 社保卡磁条坏了怎么办 鞋子长了怎么办m.s.cn 厚底皮拖鞋穿松了怎么办 白色帆布鞋洗后发黄怎么办 运动鞋子买大了怎么办 格力空调出现fo怎么办 绝味鸭脖代金券的附券撕了怎么办 耐克鞋子开胶了怎么办 苹果6s自动重启怎么办 钱不够想买手机怎么办 安卓机屏幕密码忘了怎么办 屏幕解锁密码忘了怎么办 华为手机屏幕解锁密码忘了怎么办 oppo锁屏密码忘了怎么办 云助理密码忘了怎么办 购买方发票丢了怎么办 普票发票联丢失怎么办 唯品金融没还款怎么办 金点原子锁打不开了怎么办 87彩店注册不了怎么办 微店如果不退款怎么办 微信上微商被骗怎么办 微商代理不做了怎么办 微店拒收不退款怎么办 在微商买东西被骗怎么办 云集买家买东西不退款怎么办 微信红包密码忘记了怎么办 微信购物不退货怎么办 微信隐私设置无法添加怎么办 微信支付被限额怎么办 微信发现没有购物怎么办 微信转账钱被骗怎么办 玩连环夺宝输了好多钱怎么办 厘米秀换不了装怎么办 社保只缴纳两年怎么办 502盖子粘到手上怎么办 口红粘在盖子上怎么办 玫瑰手杖永久错过了怎么办 手指沾到502胶水怎么办 我退款了货到了怎么办 世纪天成账号被盗什么也没绑怎么办