SharePoint文档库中的文件和文件夹
原文地址:http://www.cnblogs.com/erucy/p/4234318.html
本节中所阐述的内容,主要适用于SharePoint文档库中的文件和文件夹,以及列表中的文件夹。系统中的其他文件(如_layouts中的文件、配置文件、程序文件等)不在本章节的讨论范围之内。
(一)概述
SharePoint的文档库是文件系统和列表系统的双重结构:文档库中的文件既是一个文件也是一个列表条目;文档库和列表中的文件夹既是一个文件夹也是一个列表条目(普通列表和文档库的文件夹略微有些不同)。
那么,既然文档/文件夹/普通列表条目都可以用同样的列表条目的形式表现,那么如何区分一个列表条目究竟是一个条目/文件,还是一个文件夹呢?有两种方法(在后面会看到代码示例):
(1) 通过SPListItem的ContentType属性,根据条目的内容类型判断。在SharePoint 2007及2010中,文件夹是一种特殊的内容类型,凡是继承了文件夹内容类型的条目,都是以文件夹的形式存在的。
(2)通过SPListItem的FileSystemObjectType属性判断,该属性的类型是SPFileSystemObjectType枚举,如果值为Folder表示该条目是一个文件夹,如果值为File表示该条目是一个文件/普通条目。
(二)常用对象和操作
1、文件和文件夹的获取
文件和文件夹的获取主要有如下几种方式:
(1) 使用SPWeb的GetFile(string url)和GetFolder(string url)方法,根据文件/文件夹的相对网站或相对服务器地址获取到文件/文件夹对象。但需要注意的是,即使该Url中不存在任何文件或文件夹,同样可以获 取到相应的SPFile或SPFolder对象,程序不会抛出任何异常。但是我们可以通过SPFile或SPFolder的Exists属性(bool类 型)来判断这个文件或文件夹是否确实存在。
(2) 使用SPWeb的RootFolder属性或SPList的RootFolder属性获取网站或列表的根文件夹对象。
(3) 使用后文提到的交叉访问的方法,先获取到列表条目(SPListItem),再获取到与之对应的文件或文件夹。
(4)使用后文将要介绍的遍历方法。
2、文件系统和列表系统的交叉访问
既然SharePoint文件系统有双重性质,就必然会涉及到交叉访问的问题,也就是说当得到了一个文件/文件夹之后,如何得到与之对应的列表条目;以及得到了列表条目之后,如何得到与之对应的文件或文件夹。
这 里首先要说明一下什么时候使用文件/文件夹,什么时候使用列表条目,换句话说,文件/文件夹与列表条目之间在使用上的本质区别在什么地方。文件中保存的是 文件的内容、文件名称、文件大小、创建时间等一些文件固有属性;文件夹保存的是文件夹名称,文件夹中的文件和子文件夹(因此在涉及到查询或遍历范围的时 候,总是直接使用SPFolder对象);列表条目保存的是除文件和文件夹固有属性之外的一些扩展属性。当然,文件和文件夹的一些固有属性同样存放在列表 条目的一些字段中。
从实际开发应用概括地来说,如果需要获取一些属性、名称等内容,则使用列表条目;如果需要获得或修改文件内容,则使用文件;如果需要进行查询或遍历,则使用文件夹。
列表条目 →文件系统的访问: 当获取到一个列表条目之后,首先可以通过SPListItem的ContentType或FileSystemObjectType属性判断出该条目对应 的是文件还是文件夹,之后通过SPListItem的File属性或Folder属性获取到相应的文件或文件夹对象。如果使用不当(比如对文件夹对应的条 目使用了File属性),则相应的属性为null。
文件系统 → 列表条目的访问:当获取到文件或文件夹 之后,判断他们是否有对应的列表条目稍微有些复杂。当获取到文件对象之后,通过SPFile的InDocumentLibrary属性(bool类型)可 以判断文件是否在文档库中,但是这样无法区分出文档库中保存的文件和文档库中的一些视图、表单页面。当获取到文件夹对象后,通过SPFolder的 ContainingDocumentLibrary属性(Guid类型),可以判断出文件夹是否包含在文档库中,但是这种方法也无法判断出普通列表中的 文件夹。不过我们可以通过更直观的SPFile的Item属性(SPListItem类型)来进行判断,当获取一个SPFile或SPFolder对象的 Item属性之后,会分成三种情况:(1)Item属性不为空,则表示此文件或文件夹对应的列表条目;(2)Item属性为空(null),则表示此文件 或文件夹包含在列表或文档库中,但是不对应任何列表条目(可能是一些视图、表单页面或其他文件夹);(3)抛出信息为“指定的对象不属于列表”的异常,说 明这个文件或文件夹不在列表或文档库中。
在后文的文档库/列表遍历中,我们会看到相应的例子。
3、文件的读取、上传和修改
文 件的读取可以使用SPFile的OpenBinary()方法,返回文件内容的byte数组;对于比较大的文件,出于性能考虑,也可以使用SPFile的 OpenBinaryStream()方法,返回相应的Stream文件流对象,再进行读取。对于文本文件,获取其内容有一个更方便的方法,就是使用 SPWeb的GetFileAsString(string url)方法,直接得到文本文件的内容。
文件的上传与一般的集合操作相 同,使用SPFileCollection的Add方法进行。Add方法有很多种重载,归纳起来大致分为两类:使用byte[]作为参数指定文件内容(适 用与较小的文件);使用Stream作为参数指定文件流(适用于较大文件,或适合使用流格式的文件)。
通过下面的例子,展示了如何将文档库中的一个文件复制为同文件夹另一个文件(当然这里只是为了展示文件内容的操作,文件复制有一个更加直观的方法——使用SPFile的CopyTo方法):
2: {
4: {
5: SPFile sourceFile = web.GetFile("Chapters/Ch01.docx");
6: SPFolder folder = sourceFile.ParentFolder;
8: sourceFile.OpenBinaryStream());
10: }
文件的内容修改使用SPFile的SaveBinary方法,其重载的参数与文件上传类似:使用byte[]作为参数指定文件内容(适用与较小的文件);使用Stream作为参数指定文件流(适用于较大文件,或适合使用流格式的文件)。
SPFile对象的绝大部分属性都是只读的,甚至包括表示文件名的Name属性。因此,如果需要修改文件名的话,需要使用SPFile的MoveTo方法,如下面的例子所示:
2: {
4: {
5: SPFile file = web.GetFile("Chapters/Ch01.docx");
6: file.MoveTo(file.ParentFolder.Url + "/Ch01_New.docx");
8: }
4、添加文件夹
文件夹的创建方法在文档库和普通列表中稍有不同。
在文档库中,与一般的集合操作相同,直接使用SPFolderCollection的Add(string name)方法即可添加文件夹,例如下面的程序在文档库的根目录中添加一个名为“技术文档”的子文件夹:
2: {
4: {
5: SPList doclib = web.Lists["共享文档"];
6: doclib.RootFolder.SubFolders.Add("技术文档");
8: }
但是这种方法对于普通列表来说就行不通了。在文档库中,SharePoint会将我们用上述方法创建的文件夹自动关联创建一个列表条目;但是在普通 列表中,这种文件夹不会自动关联到新的列表条目上,因此在普通列表中使用这种方法创建出的文件夹,不会显示在任何一个列表视图中。在普通列表中,我们需要 使用创建一个“文件夹类型的列表条目”的方式,来新建文件夹(既然是创建一个列表条目,不要忘记最后需要调用Update方法才能创建成功):
2: {
4: {
5: SPList list = web.Lists["Chapters"];
6: SPListItem fldItem = list.AddItem();
7: fldItem.FileSystemObjectType = SPFileSystemObjectType.Folder;
8: fldItem["Title"] = "第一部分";
9: fldItem.Update();
11: }
这种方法同样适用与文档库中的文件夹创建,但不同的是需要将文件夹名称写入“FileLeafRef”字段,而不是“Title”字段。(FileLeafRef是“名称”字段的内部名称,Title是“标题”字段的内部名称)
5、在文件夹中创建列表条目
之前在创建列表条目、文件夹的时候,都是在列表的根目录中进行的,当我们需要在某个子目录中创建列表条目或子文件夹的时候,需要用到SPList的AddItem方法的一个重载:
2: SPFileSystemObjectType underlyingObjectType)
或者SPListItemCollection的Add方法的类似重载:
2: SPFileSystemObjectType underlyingObjectType)
其中第一个参数需要指定列表条目所在的子文件夹的路径(要求使用相对服务器的Url地址);第二个参数指定了要创建的列表条目的类型,即创建普通条目还是创建文件夹。下面给出了一个例子:
2: {
4: {
5: SPList list = web.Lists["Chapters"];
7: + "/第一部分");
9: SPFileSystemObjectType.File);
10: itmInFolder["Title"] = "Ch01";
11: itmInFolder.Update();
13: }
6、文件(SPFile)和文件夹(SPFolder)的常用属性
SPFile的一些常用属性如下:
|
名称 |
类型 |
说明 |
|
Exists |
bool |
文件是否存在 |
|
IconUrl |
string |
与文件类型相关联的图标的Url |
|
Item |
SPListItem |
文档对应的列表条目对象 |
|
Length |
long |
文件的大小 |
|
Name |
string |
文件名 |
|
ParentFolder |
SPFolder |
所在文件夹的对象 |
|
ServerRelativeUrl |
string |
文件相对于服务器的Url |
|
Url |
string |
文件相对于网站的Url |
SPFolder的一些常用属性如下:
|
名称 |
类型 |
说明 |
|
Exists |
bool |
文件夹是否存在 |
|
Files |
SPFileCollection |
文件夹中的文件集合 |
|
Item |
SPListItem |
文件夹对应的列表条目对象 |
|
Name |
string |
文件夹名称 |
|
ParentFolder |
SPFolder |
父文件夹的对象 |
|
SubFolders |
SPFolderCollection |
子文件夹集合 |
|
ServerRelativeUrl |
string |
文件相对于服务器的Url |
|
Url |
string |
文件相对于网站的Url |
(三)遍历
文件系统的遍历是指按照文件夹的层级结构遍历文档库、列表的文件夹和列表条目。遍历主要有三种方式:(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属性指定查询范围的文件夹。通过这一 特性,我们可以不指定任何查询条件,就相当于返回范围内的所有内容了。使用这种方法可以在所有的列表中进行遍历,自然也包括了文档库,下面是一个例子:
2: {
3: SPQuery query = new SPQuery();
4: query.Folder = folder;
5: SPListItemCollection items = list.GetItems(query);
6: if (items.Count == 0) return;
7:
9: {
" ");
12: {
13: Console.WriteLine("[{0}]", item.DisplayName);
14: GoThroughList(list, item.Folder, level + 1);
16: else
17: Console.WriteLine(item.DisplayName);
19: }
20:
22: {
24: {
26: {
27: SPList list = web.Lists["Chapters"];
28: GoThroughList(list, list.RootFolder, 0);
30: }
31: }
(四)列表附件
列表的附件也是文件系统的一部分,它依附于普通列表的列表条目之上(文档库没有附件),它的操作在一些地方和文档库中文档的操作非常类似。
1、附件的读取
一 个列表条目的附件可以使用SPListItem的Attachments属性访问,该属性是SPAttachmentCollection类型。这个类型 在SharePoint中是一个比较特殊的类型,其特殊之处在于不存在SPAttachment类型。那么SPAttachmentCollection 这个集合中存放的又是什么呢?是附件的文件名。通过使用SPWeb的GetFile方法,可以获取到附件对应的SPFile对象,之后就可以和 SPFile对象一样进行读取和修改了。读取的方法可以参考下面的程序:
using(SPSite site = new SPSite("http://sp2010/book")) 2: { 3: using(SPWeb web = site.OpenWeb()) 4: { 5: SPListItem item = web.List["Chapters"].Items[0]; 6: string urlPrefix = item.Attachments.UrlPrefix; 7: foreach(string attName in item.Attachments) 8: { 9: SPFile file = web.GetFile(urlPrefix + attName); 10: Console.WriteLine(attName + ":" + file.Length.ToString()); 11: } 12: } 13: }
可以看到,这段程序中除了GetFile之外的一个关键点在于SPAttachmentCollection的UrlPrefix这个属性。列表的 所有附件都保存在列表根目录的Attachments目录中,并按照列表条目的ID划分出子文件夹,通过直接使用UrlPrefix属性,获得某个列表条 目所有附件所在文件夹的完整路径。
2、附件的添加和删除
附件的添加和删除与文件的上传和删除类似。在添加的时候,使用集合类——即SPAttachmentCollection的Add方法,与上传文件 的区别在于,这个Add方法没有其他重载,只能指定附件的文件名和byte[]形式的文件内容,这也就意味着列表条目的附件不适合存放大文件;删除的时 候,使用SPAttachmentCollection这个集合类的Delete方法和Recycle方法删除附件。
但是就像列表条目的更新一样,在修改字段值之后,需要调用SPListItem的Update方法才能使修改生效,在使用 SPAttachmentCollection的Add、Delete和Recycle方法之后,必须Update一下列表条目,才能使附件的更新生效。 为了使对附件的操作更加简便,SPAttachmentCollection提供了三个类似的方法:AddNow、DeleteNow和 RecycleNow,使用这三个方法上传或删除附件后,可以直接生效,无需对列表条目进行Update。

浙公网安备 33010602011771号