日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.Net读取XP文件夹中的Thumbs.db文件

發布時間:2025/5/22 asp.net 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .Net读取XP文件夹中的Thumbs.db文件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一般在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;

};

?

注意上面的定義里面,[Create/Open]Stream就是創建和打開“文件”的方式,而 [Create/Open]Storage就是創建和打開“文件夾”的方式“文件夾”里面不是可以包含其他的文件夾嗎?下面是IStream接口的定義:

??? MIDL_INTERFACE("0000000c-0000-0000-C000-000000000046")

??? IStream : public ISequentialStream

??? {

??? public:

??????? virtual /* [local] */ HRESULT STDMETHODCALLTYPE Seek(

??????????? /* [in] */ LARGE_INTEGER dlibMove,

??????????? /* [in] */ DWORD dwOrigin,

??????????? /* [out] */ ULARGE_INTEGER *plibNewPosition) = 0;

???????

?????? ?virtual HRESULT STDMETHODCALLTYPE SetSize(

??????????? /* [in] */ ULARGE_INTEGER libNewSize) = 0;

???????

??????? virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo(

??????????? /* [unique][in] */ IStream *pstm,

??????????? /* [in] */ ULARGE_INTEGER cb,

??????????? /* [out] */ ULARGE_INTEGER *pcbRead,

??????????? /* [out] */ ULARGE_INTEGER *pcbWritten) = 0;

???????

??????? virtual HRESULT STDMETHODCALLTYPE Commit(

??????????? /* [in] */ DWORD grfCommitFlags) = 0;

???????

??????? virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0;

???????

??????? virtual HRESULT STDMETHODCALLTYPE LockRegion(

??????????? /* [in] */ ULARGE_INTEGER libOffset,

??????????? /* [in] */ ULARGE_INTEGER cb,

??????????? /* [in] */ DWORD dwLockType) = 0;

???????

??????? virtual HRESULT STDMETHODCALLTYPE UnlockRegion(

??????????? /* [in] */ ULARGE_INTEGER libOffset,

??????????? /* [in] */ ULARGE_INTEGER cb,

??????????? /* [in] */ DWORD dwLockType) = 0;

???????

??????? virtual HRESULT STDMETHODCALLTYPE Stat(

??????????? /* [out] */ __RPC__out STATSTG *pstatstg,

??????????? /* [in] */ DWORD grfStatFlag) = 0;

???????

??????? virtual HRESULT STDMETHODCALLTYPE Clone(

??????????? /* [out] */ __RPC__deref_out_opt IStream **ppstm) = 0;??

??? };

?

?IStream的用法跟.Net里面的System.IO.Stream的用法類似,其中IStream::Commit函數的作用就是將內存中的修改保存到硬盤中。

一般來說,結構化存儲文件的“文件夾”IStorage里面都會有一個IStream保存該“文件夾”的目錄即說明“文件夾”里面有哪些文件。

Thumbs.db文件的文件描述

既然我們已經知道IStorageIStream的概念和用法了,回過頭來看看Thumbs.db文件,Thumbs.db文件中有一個名稱為“Catalog”的 IStream保存了整個Thumbs.db文件里面緩存的縮略圖的文件名列表。

它包含兩段內容,第一段內容的結構叫做CatalogHeader(當然這也是我們隨便取的因為微軟并沒有公開Thumbs.dbAPI),保存了所有縮略圖的大小,是32x32的,還是64x64之類的,另外還有一個重要的變量保存了縮略圖文件的個數。下面是這個數據結構的聲明,因為沒有對應的COM API,所以我們直接在C#中聲明了。

??? [Interop.StructLayout(Interop.LayoutKind.Sequential)]

??? public struct CatalogHeader

??? {

??????? public short Reserved1;

?

??????? public short Reserved2;

?

??????? public int ThumbCount;

?

??????? public int ThumbWidth;

?

??????? public int ThumbHeight;

??? }

?

注意聲明上面的StructLayout屬性,由于.Net是即時編譯的系統,在編譯的過程當中,通常情況下,JIT會根據當前系統內存和CPU的架構,為結構生成最優的內存布局以便在訪問結構體的時候能夠達到最快的速度因此JIT可能會調整結構的一些成員在內存布局的順序。 由于我們是在讀取COM生成的數據,C++編譯器可沒有做到這一點,所以LayoutKind.Sequential告訴JIT編譯器,不要隨意更改結構成員在內存中的布局。而ReveredX屬性的存在是因為這個結構是我們猜的結構,前兩個屬性沒猜出來。

第二段內容就是縮略圖的“文件名”信息了,除了名字以外,還保存了縮略圖生成的時間—以便同名文件更新的時候可以生成新的縮略圖,還有一個莫名其妙的 ItemId—估計是用來提高檢索縮略圖速度的,當然還有兩個沒猜出來的屬性。下面是這個成員的結構定義:

??? [Interop.StructLayout(Interop.LayoutKind.Sequential)]

??? public struct CatalogItem

??? {

??????? public int Reserved1;

?

??????? private int m_ItemId;

??????? public int ItemId

??????? {

????? ??????get { return m_ItemId; }

??????????? set

??????????? {

??????????????? m_ItemId = value;

??????????????? BuildItemIdString(m_ItemId);

??????????? }

??????? }

?

??????? public DateTime Modified;

?

??????? public string FileName;

?

??????? public short Reserved2;

?

??????? // 自己添加的新域

??????? public string ItemIdString

??????? {

??????????? get;

??????????? private set;

??????? }

?

??????? private void BuildItemIdString(int itemId)

??????? {

??????????? var temp = itemId.ToString();

??????????? var buffer = new char[temp.Length];

??????????? for (int i = 0; i < temp.Length; ++i)

??????????????? buffer[i] = temp[temp.Length - i - 1];

?

??????????? ItemIdString = new string(buffer);

??????? }

??? }

?

不知道是什么原因,在Thumbs.db文件當中,數據都是以倒序保存的,比如字符串就是倒序的, 而整形的四個字節也是倒序排列的—難道微軟真的不想讓第三方程序員訪問Thumbs.db文件?

Thumbs.db文件的讀取

既然已經知道文件結構,訪問的方式就不多講了,無非就是先用StgOpenStorage函數打開結構化存儲文件,獲取IStorage接口的引用,讀取“Catalog”獲得Thumbs.db文件的目錄,接著獲得每一個縮略圖“文件名”對應的CatalogItem,使用CatalogItem的倒序ItemId拿到具體縮略圖的IStream指針,然后通過IStream::Read的方法來讀取縮略圖的內容,最后顯示在窗體上。唯一要注意的是,每一個縮略圖IStream的前12個字節(3個整形)不是縮略圖的內容,不能用的,因此在讀取的時候跳過那三個字節好了。

因為.Net只提供了IStream的定義,而IStorage的定義需要我們自己生成。這個接口手工編寫.Net對應的接口有點麻煩因此建議去http://www.pinvoke.net/ 去搜索別人已經寫好的定義。

代碼下載:

/Files/killmyday/ThumbLib.zip

總結

以上是生活随笔為你收集整理的.Net读取XP文件夹中的Thumbs.db文件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。