在Explorer中,選擇“詳細”視圖,可以看到很多文件屬性,如圖片的分辨率,MP3的藝術家、比特率,視頻文件的分辨率等等等等;這些數據,有時候在C#中可能很難獲取,比如圖片的分辨率,需要用Image.FromFile得到Image類,然後才能得到分辨率數據,但是把圖片加載到內存中,一是會加大內存開銷,二是會更耗時。所以,今天我們就來說說怎麼在C#中獲取到文件的詳細屬性。
在你的項目中添加對C:\Windows\System32\shell32.dll的引用,我們在前面一期《C#中使用SHFileOperation調用Windows的復制文件對話框》中也用到了這個動態鏈接庫,不過當時是使用映射的方式,如今我們將其引用,直接使用。
Shell32;
代碼實現
GetProperties這個方法返回所有屬性值,在我的Win7 Pro 64bit 上,返回了287個屬性!可以想象,信息是很豐富的,但是速度也是夠慢的。
可以看到,上面代碼用了一個循環,獲取屬性名和屬性值時都是通過i來索引的。那麼,我們是不是就能不通過循環,而直接用下標來獲取想要的屬性呢?代碼如下:
GetPropertyByIndex在我的系統環境上,分辨率“尺寸”下標是31,那麼我只需要GetPropertyByIndex(@“D:\test.jpg”,31)就可以獲取到分辨率信息了。但是特別需要注意,“尺寸”屬性的下標,在不同的Windows版本(XP,Vista,Win7,Win2003等)不一定是一樣的。
ok,我們還注意到每個屬性都有對應的一個“屬性名”,那麼,我們能不能通過屬性名來獲取屬性值呢,這樣會比使用下標保險多了吧。代碼如下:
GetProperty這個方法是我一開始寫的,通過在while裡面加上屬性名的判斷,直到找到對應的屬性名,則返回相應的屬性值。
不過這個方法還是不夠簡潔,“尺寸”屬性在31,意味著每一次都需要循環31次才能拿到我要的值,如果我要獲取的屬性名下標為287(參看上面),那麼次數將更多,於是,我又對代碼做了一些優化:
GetPropertyEx_propertyIndex用於存儲屬性名與其下標,用Dictionary是因為_propertyIndex[key]的時間復雜度是O(1)。然後在GetPropertyEx方法中找到屬性名對應的下標,直接返回該下標的屬性值。InitPropertyIndex方法只會被調用一次。
好了,我們現在通過屬性名來獲取屬性值,在不同系統之間應該不會有問題了吧?
不一定,原因你肯定也想到了,如果是在一個英文windows上,它的屬性名裡面不會有“尺寸”,對應的應該是“Resolution”之類的(我沒有英文版系統,所以只是猜測),也不會有“名稱”屬性,而是“Name”;
總結一下,
方法名
適用
不適用
GetPropertyByIndex
不同語言的系統
不同版本的系統
GetPropertyEx
不同版本的系統
不同語言的系統
所以,根據你的程序可能的運行環境,選擇適合你的方法;
再思考:要能在不同語言不同版本的系統將通用,該怎麼辦?
我目前想到的:建立同一個屬性名在不同語言間的對應關系,如”尺寸”對應” Resolution”,然後,在代碼裡獲取到系統語言,將屬性名“翻譯”成該語言,即可通過翻譯後的屬性名找到對應的屬性值了。歡迎有實現了本方法或者更好方法的同學一起來討論。