.Net读取XP文件夹中的Thumbs.db文件2011-01-22 博客园 donjuan一般在XP文件夹里面,特别是图片和视频文件夹里有一个文件—Thumbs.db文件。这个文件是XP用来缓存图片和影音文件的缩略图的,有了这个文件,XP在打开保存大量图片文件的文件夹的时候,显示速度会明显比没有Thumbs.db文件的文件夹快—因为后者需要实时生成缩略图。最近在做一个自己的图片管理程序,需要快速生成缩略图,就想到复用这个文件,这样我的程序可以无缝地继承视窗系统的资源管理器功能。因为Thumbs.db文件的文件结构和访问API没有被公开,所以在Google查了一些资料,发现Thumbs.db文件采用的是结构化存储文件(Structured Storage File)结构,这个文件在COM时代非常的流行,不知道为什么在.Net里面,微软把这个文件结构扔掉了。结构化存储概述结构化存储文件结构说白了就是一个保存在文件里面的文件系统,就是说在一个结构化存储文件里面,保存有“文件夹”信息,也保存有“文件”信息和其内容。例如,我们熟悉的Winrar的打包多个文件的过程,就可以使用结构化存储文件结构来保存(当然啦,我没有Winrar的源代码,不是说Winrar就是这样实现打包的啊)。使用结构化存储文件的一个好处是,使得更新文件内容非常方便。 举个例子,比如我们日常使用的Word吧,当我们编辑一个文件的时候,如果Word采用的顺序存储结构—文件内容是按照内容的逻辑结构顺序存储在磁盘里的,即在硬盘里,第一页保存在第二页的前面。顺序存储方式的问题在于,它使得修改Word文档的时候,会变得非常麻烦。假设你的文档有几千页,当你增删第一页的内容的时候,顺序存储的方式就要求你必须移动后面几千页内容—可以想象到这个过程有多慢了。 如果我们将Word文档看作一个小的文件系统的话,那么对于文档中的每一页我们可以看成是一个“文件夹”,然后所有的文字段落可以看成是“文件夹”里面的文件。如果文档里面插入了图片的话,可以另外在“文件夹”里创建一个小的文件夹—“图片”文件夹,而在使用到这个图片的位置上加入一个快捷方式链接到每一页的内容里就可以了。下图演示了前一段描述的概念(注意-我没有看到Office的源代码,上述内容只不过是我的一个小猜想而已):

结构化存储文件的COM接口 刚才讲完了概念,在COM中,IStorage接口就相当于结构化存储文件中的 “文件夹”,而IStream接口就是“文件”啦。下面就是IStorage的接口:
MIDL_INTERFACE("0000000b-0000-0000-C000-000000000046")
IStorage : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE CreateStream(
/* [string][in] */ __RPC__in const OLECHAR *pwcsName,
/* [in] */ DWORD grfMode,
/* [in] */ DWORD reserved1,
/* [in] */ DWORD reserved2,
/* [out] */ __RPC__deref_out_opt IStream **ppstm) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE OpenStream(
/* [string][in] */ const OLECHAR *pwcsName,
/* [unique][in] */ void *reserved1,
/* [in] */ DWORD grfMode,
/* [in] */ DWORD reserved2,
/* [out] */ IStream **ppstm) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateStorage(
/* [string][in] */ __RPC__in const OLECHAR *pwcsName,
/* [in] */ DWORD grfMode,
/* [in] */ DWORD reserved1,
/* [in] */ DWORD reserved2,
/* [out] */ __RPC__deref_out_opt IStorage **ppstg) = 0;
virtual HRESULT STDMETHODCALLTYPE OpenStorage(
/* [string][unique][in] */ __RPC__in_opt const OLECHAR *pwcsName,
/* [unique][in] */ __RPC__in_opt IStorage *pstgPriority,
/* [in] */ DWORD grfMode,
/* [unique][in] */ __RPC__deref_opt_in_opt SNB snbExclude,
/* [in] */ DWORD reserved,
/* [out] */ __RPC__deref_out_opt IStorage **ppstg) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo(
/* [in] */ DWORD ciidExclude,
/* [size_is][unique][in] */ const IID *rgiidExclude,
/* [unique][in] */ SNB snbExclude,
/* [unique][in] */ IStorage *pstgDest) = 0;
virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
/* [string][in] */ __RPC__in const OLECHAR *pwcsName,
/* [unique][in] */ __RPC__in_opt IStorage *pstgDest,
/* [string][in] */ __RPC__in const OLECHAR *pwcsNewName,
/* [in] */ DWORD grfFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE Commit(
/* [in] */ DWORD grfCommitFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE EnumElements(
/* [in] */ DWORD reserved1,
/* [size_is][unique][in] */ void *reserved2,
/* [in] */ DWORD reserved3,
/* [out] */ IEnumSTATSTG **ppenum) = 0;
virtual HRESULT STDMETHODCALLTYPE DestroyElement(
/* [string][in] */ __RPC__in const OLECHAR *pwcsName) = 0;
virtual HRESULT STDMETHODCALLTYPE RenameElement(
/* [string][in] */ __RPC__in const OLECHAR *pwcsOldName,
/* [string][in] */ __RPC__in const OLECHAR *pwcsNewName) = 0;
virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
/* [string][unique][in] */ __RPC__in_opt const OLECHAR *pwcsName,
/* [unique][in] */ __RPC__in_opt const FILETIME *pctime,
/* [unique][in] */ __RPC__in_opt const FILETIME *patime,
/* [unique][in] */ __RPC__in_opt const FILETIME *pmtime) = 0;
virtual HRESULT STDMETHODCALLTYPE SetClass(
/* [in] */ __RPC__in REFCLSID clsid) = 0;
virtual HRESULT STDMETHODCALLTYPE SetStateBits(
/* [in] */ DWORD grfStateBits,
/* [in] */ DWORD grfMask) = 0;
virtual HRESULT STDMETHODCALLTYPE Stat(
/* [out] */ __RPC__out STATSTG *pstatstg,
/* [in] */ DWORD grfStatFlag) = 0;
};