(三)遍歷
文件系統的遍歷是指按照文件夾的層級結構遍歷文檔庫、列表的文件夾和列表條目。遍歷主要有三種方式:(1)直接使用文件系統對象模型進行遍歷;(2)使用SPDocumentLibrary進行遍歷;(3)藉助SPQuery進行遍歷。
1、SPList的Items和Folders屬性
在介紹真正的遍歷之前,有必要先解釋一下這兩個重要的屬性。
這兩個屬性返回的都是SPListItemCollection類型,它們分別返回了列表中所有的普通條目(或文件),以及列表中的所有文件夾。不論這些條目、文件、文件夾在列表的層次結構中處於什麼位置,Items和Folders屬性都會獲得列表中的全部內容,而且是不分層次結構的。
因此,實際上這兩個屬性的使用頻率要比遍歷操作高得多(尤其是Items屬性)。當我們需要獲取列表中的所有普通條目或者文件的時候(一般我們不太關心文件夾本身),就需要使用Items屬性。這個屬性的存在使得在操作文檔庫的時候,要比操作磁盤的文件系統方便得多——可以直接得到文檔庫中任意層次下的所有文件!
順便提一下,Items和Folders合在一起,就是列表中所存儲的所有內容。在SharePoint的對象模型中,SPList有一個屬性是ItemCount,返回列表中所存儲的所有條目的數目,經常有人認爲這個屬性就是spList.Items.Count,其實不然。實際上,spList.ItemCount應該等於spList.Items.Count + spList.Folders.Count。
2、使用文件系統對象模型進行遍歷
與.NET中傳統的FileInfo/DirectoryInfo類似地,SPFile和SPFolder也有着明顯的層級結構,通過使用SPFolder的Files(SPFileCollection類型)和SubFolders(SPFolderCollection類型)可以直接按照文件夾的層級結構使用foreach等方法進行遞歸遍歷,在此不再做示例。
這種方式的便利雖然直觀而且簡單,但是有兩個不容忽視的問題:
(1) 這種方式僅適用於文檔庫,普通列表雖然可以有Folder,但是沒有File,無法直接進行遍歷;
(2) 使用這種方式遍歷的時候,需要執行的帳號有“瀏覽目錄”的權限(如圖2-10);但是在SharePoint內置的權限級別中,只有“參與討論”及以上的權限級別才包含這個權限,換句話說,對於網站的“讀者”或“查看者”,是無法正常執行使用這種方式進行遍歷的程序的。
3、使用SPDocumentLibrary進行遍歷
這種方法藉助了SPList的一個專門針對文檔庫設計的子類:SPDocumentLibrary。雖然該方法同樣只能應用於文檔庫,但是解決了直接使用文件系統對象模型遍歷的第二個問題,即權限問題。
SPDocumentLibrary作爲SPList的子類,提供了一個特殊的方法,叫做GetItemsInFolder——顧名思義,是用於獲取文檔庫的某個文件夾下的內容的。此外,SPDocumentLibrary還提供了另外一個比較有用的屬性,IsCatalog(bool類型),用於判斷一個文檔庫是否是網站的配置文檔庫(比如列表模板庫、網站模板庫、Web部件庫、母版頁庫等)。使用SPDocumentLibrary進行文檔庫遍歷的具體方法可以參看下面這個示例:
1: static void GoThroughDocLib(SPDocumentLibrary doclib,
2: SPFolder folder, int level)
3: {
4: SPListItemCollection items =
5: doclib.GetItemsInFolder(doclib.DefaultView, folder);
6: if (items.Count == 0) return;
7:
8: foreach (SPListItem item in items)
9: {
10: for (int i = 0; i < level; i++) Console.Write(" ");
11: if (item.FileSystemObjectType == SPFileSystemObjectType.Folder)
12: {
13: Console.WriteLine("[{0}]", item.Name);
14: GoThroughDocLib(doclib, item.Folder, level + 1);
15: }
16: else
17: Console.WriteLine(item.File.Name);
18: }
19: }
20:
21: static void Main(string[] args)
22: {
23: using(SPSite site = new SPSite("http://sp2010/book"))
24: {
25: using(SPWeb web = site.OpenWeb())
26: {
27: SPDocumentLibrary doclib = web.Lists["共享文檔"] as SPDocumentLibrary;
28: GoThroughDocLib(doclib, doclib.RootFolder, 0);
29: }
30: }
31: }
在本示例程序中,就應用了交叉訪問的方法,在區分了一個條目是文件還是文件夾之後,使用了SPListItem的File屬性和Folder屬性獲取其文件對象和文件夾對象。實際上,item.File.Name和item.Name是一樣的。
4、使用SPQuery進行遍歷
上述方法解決了文件系統遍歷的權限問題,但是仍然只是侷限在文檔庫中。實際上,上面一種方法是SharePoint 2003時代遺留下來的方法,到了2007和2010時代,普通列表中也增加了文件夾的結構,因此也就衍生了新的遍歷方法——藉助SPQuery的遍歷。
SPQuery的主要作用是進行列表查詢——從類名上就可以看出這一點。在查詢的時候,可以通過其Folder屬性指定查詢範圍的文件夾。通過這一特性,我們可以不指定任何查詢條件,就相當於返回範圍內的所有內容了。使用這種方法可以在所有的列表中進行遍歷,自然也包括了文檔庫,下面是一個例子:
1: static void GoThroughList(SPList list, SPFolder folder, int level)
2: {
3: SPQuery query = new SPQuery();
4: query.Folder = folder;
5: SPListItemCollection items = list.GetItems(query);
6: if (items.Count == 0) return;
7:
8: foreach (SPListItem item in items)
9: {
10: for (int i = 0; i < level; i++) Console.Write(" ");
11: if (item.FileSystemObjectType == SPFileSystemObjectType.Folder)
12: {
13: Console.WriteLine("[{0}]", item.DisplayName);
14: GoThroughList(list, item.Folder, level + 1);
15: }
16: else
17: Console.WriteLine(item.DisplayName);
18: }
19: }
20:
21: static void Main(string[] args)
22: {
23: using(SPSite site = new SPSite("http://sp2010/book"))
24: {
25: using(SPWeb web = site.OpenWeb())
26: {
27: SPList list = web.Lists["Chapters"];
28: GoThroughList(list, list.RootFolder, 0);
29: }
30: }
31: }
本程序大體結構與使用SPDocumentLibrary進行遍歷的程序完全相同,只是使用的方法不同。關於SPQuery的使用,在後文還有更加詳細的講解。