一、需求分析

公司需要将存在于旧系统(TFS)所有的文档迁移至新系统(SharePoint 2013)。现已经将50G以上的文档拷贝到SharePoint 2013 Server上。这些文档是一些不规则的资料,除了常见的Office文件、PDF,还包括图片、RAR等,甚至还包括一些快捷方式(.link)这类的"脏数据"。除此之外,这些存在于TFS中的文档,名称也是"不规则",即包含了SharePoint 2013文档命名不支持的字符如"&", "\"", "?", "<", ">", "#", "{", "}", "%", "~", "/", "\\"。所以,这对导入又增加了复杂度。

了解了文档内容和命名规则后,接下来就是分析怎样导入至SharePoint文档库中:

  • 首先,每一个二级文件夹的命名是有规则的,正好是项目编号(Project Number),如GCP-xxxx-xxx-xxx。再根据此编号创建一个子站点。
  • 值得一提的是,根据编号创建的子站点并不是随意创建的,而是需要考虑究竟要在哪一个Site Collection下创建子站点,并且还要给予独立权限的分配,即为子站点打断权限继承,为其增加两个组(Owners和Members),并向组里添加对应的人员。
  • 对应的创建规则存在于如下List中

其中Project Number即项目编号,与TFS中文件夹的名称一致。Department 即需要将此子站点创建于哪个Site Collection中,包含两个值SMO和CO。PM列是一个Person Or Group类型的字段,需要将此字段的值加入到Owner组,Domain Group列也是一个Person Or Group类型的字段,需要将此字段的值加入到Member组中。

  • 接下来,是最重要的一步,找到最佳实践去创建各个Level的文件夹并传入文档。

二、分析和构建导入程序

首先,文件夹的目录结构如下图所示:

文档目录结构图

  • 根据上图文档目录结构图,分割字符串(E:\TFS\GCP0401-S\4.Project Management\3 Document Management\TMF),获取文件夹的名称,即Project Number(GCP0401-S)。然后根据此Project Number找到对应的Department、PM、Domain Group,最后创建子站点。逻辑代码如下图所示:
private SPWeb CreateSubSite(string webUrl, string webTitle, string description){var result = (from e in projectInfos where e.ProjectNumber == webUrl && tempArray.Contains(webUrl) select e).FirstOrDefault();if (result==null){logger.Debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&以下Sub Site没有创建********");logger.Debug("Web Url="+webUrl);logger.Debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*********");return null;}logger.Debug("开始创建在Site Collection:"+result.Department.ToUpper());using (SPSite site = result.Department.ToUpper()=="SMO"? new SPSite("http://sp/sites/smo"):new SPSite("http://sp/sites/cro")){//{*/using(SPSite site=new SPSite("http://reus")){using (SPWeb web = site.OpenWeb()){try{SPWeb subWeb = null;if (site.AllWebs[webUrl].Exists){subWeb = site.AllWebs[webUrl];}else{logger.Debug("不存在"+webUrl+",则创建新的WebSite");//不存在则创建新的WebSitesubWeb = site.AllWebs.Add(webUrl, webTitle, description, 1033, "STS#0", true, false);string groupTitleForOwners = subWeb.Title + " Owners";subWeb.AssociatedOwnerGroup = EnsureGroup(subWeb,groupTitleForOwners , "Full Control");string groupTitleForMembers = subWeb.Title + " Members";subWeb.AssociatedMemberGroup = EnsureGroup(subWeb,groupTitleForMembers , "Edit");subWeb.Groups[groupTitleForOwners].AddUser(subWeb.Site.Owner);if (result.PM!=null){subWeb.Groups[groupTitleForOwners].AddUser(result.PM);}if (result.DomainGroup!=null){subWeb.Groups[groupTitleForMembers].AddUser(result.DomainGroup);}subWeb.Update();logger.Debug(webUrl+"创建成功");richTextBox2.Text += webUrl + "创建OK" + "\r\n";}return subWeb;}catch (Exception es){logger.Debug(es.ToString());return null;}}}}

  • 从上文档目录结构图可以分析出,二级目录是项目编号,即对应要创建的子站点。在此目录下有"无限级"的子文件夹。那应该怎样在子站点的文档库中创建如此多的文件夹呢,这需要好好考虑一下。对,用递归,得到每一个分支最底层的文件夹路径即可。具体实现如下所示:
private void GetDeepestFoleder(string sDir){string dir = string.Empty;try{foreach (string path in Directory.GetDirectories(sDir)){dir = path;if (!arrayList.Contains(dir)){arrayList.Add(dir);}arrayList.Remove(dir.Substring(0, dir.LastIndexOf("\\")));GetDeepestFoleder(dir);}}catch (Exception excpt){logger.Debug(excpt.ToString());}}

  • 得到所有最内层文件夹的URL之后,接着就是在SharePoint 文档库中创建一级一级的文件夹了。
private void CreateForderForDocumentLibrary(string folderUrl, SPWeb currentWeb){try{SPFolder newFolder = null;string spFolderUrl = currentWeb.ServerRelativeUrl  + "/Shared Documents";logger.Debug("SPFolder Url="+spFolderUrl);//分割字符串,得到父子Folder的Url,在文档库中创建文件夹foreach (string strUrl in folderUrl.Split('\\')){//todo:有空格会报错吗?string tempStrUrl = strUrl.Trim();//SharePoint 文档库中文件名有严格的格式要求var r = new[] { "&", "\"", "?", "<", ">", "#", "{", "}", "%", "~", "/", "\\"}.Any(tempStrUrl.Contains);if (r){tempStrUrl = tempStrUrl.Clean();}if (tempStrUrl.StartsWith(".") || tempStrUrl.EndsWith(".")){tempStrUrl = tempStrUrl.Replace(".", "-");}          spFolderUrl += "/" + tempStrUrl;logger.Debug("SPFolder Url="+spFolderUrl);SPList list = currentWeb.Lists.TryGetList("Documents");SPFolderCollection folderCollection = list.RootFolder.SubFolders;newFolder = folderCollection.Add(spFolderUrl);logger.Debug(spFolderUrl + "创建成功");}}catch (Exception ex){logger.Debug(ex.ToString());throw;}}

  • 以上代码逻辑中包含了字符串的处理,因为SharePoint 2013的文档、文件夹命名有严格的要求,不能包含非法字符。并且也不能以字符 "."开始或者结束。所以添加了字符串处理操作功能。
public static class MyStringExtention{public static string Clean(this string s){StringBuilder sb = new StringBuilder(s);//"&", "\"", "?", "<", ">", "#", "{", "}", "%", "~", "/", "\\" uu.uu可以,但uu.就不行sb.Replace("&", "-");sb.Replace("\"", "-");sb.Replace("?", "-");sb.Replace("<", "-");sb.Replace(">", "-");sb.Replace("#", "-");sb.Replace("{", "-");sb.Replace("}", "-");sb.Replace("%", "-");sb.Replace("~", "-");sb.Replace("/", "-");sb.Replace("\\", "-");// sb.Replace(".", "-");return sb.ToString();}}

  • 在成功创建了子站点并在文档库中创建了所有文件夹后,接下来就是将文档上传至指定的文件夹中了。所以接下来, 需要获取指定目录下所有的文件,我使用了一个队列来保存文件路径, 而不是使用递归或者使用.NET 4.0提供的基于文件迭代的功能(Directory.EnumerateFiles)来获取所有文件,原因有2点:
    • Directory.EnumerateFiles内置的递归方法容易抛出异常,比如没有权限访问等。
    • Queue<String> 避免了多次递归时调用堆栈从而会创建大数组。
private IEnumerable<string> GetFiles(string path){Queue<string> queue = new Queue<string>();queue.Enqueue(path);while (queue.Count > 0){path = queue.Dequeue();try{foreach (string subDir in Directory.GetDirectories(path)){queue.Enqueue(subDir);}}catch (Exception ex){logger.Debug("===========发生错误啦*========================");logger.Debug(ex.ToString());logger.Debug("===========发生错误了========================");}string[] files = null;try{files = Directory.GetFiles(path);}catch (Exception ex){logger.Debug("===========发生错误啦&========================");logger.Debug(ex.ToString());logger.Debug("===========发生错误了========================");}if (files != null){for (int i = 0; i < files.Length; i++){yield return files[i];}}}}

  • 在获取了所有文件之后,上传至指定文档库即可,别忘记处理非法字符。
private void UploadFileToDocumentLibrary(string folderUrl, string filePath, SPWeb currentWeb){try{//todo:不同文件名字相同会覆盖吗todoSPFolder newFolder = null;string spFolderUrl = currentWeb.ServerRelativeUrl+ "/Shared Documents";//极端情况 GCP0117 TFS List.xls//分割字符串,得到父子Folder的Url,在文档库中创建文件夹foreach (string strUrl in folderUrl.Split('\\')){//todo:有空格会报错吗?string tempStrUrl = strUrl.Trim();//SharePoint 文档库中文件名有严格的格式要求var result = new[] { "&", "\"", "?", "<", ">", "#", "{", "}", "%", "~", "/", "\\" }.Any(tempStrUrl.Contains);if (result){tempStrUrl = tempStrUrl.Clean();}if (tempStrUrl.StartsWith(".") || tempStrUrl.EndsWith(".")){tempStrUrl = tempStrUrl.Replace(".", "-");}spFolderUrl += "/" + tempStrUrl;}newFolder = currentWeb.GetFolder(spFolderUrl);string fileName = System.IO.Path.GetFileName(filePath);//SharePoint 文档库中文件名有严格的格式要求var r=new[] { "&", "\"", "?", "<", ">", "#", "{", "}", "%", "~", "/", "\\"}.Any(fileName.Contains);if (r){logger.Debug("***********File Name包含了Invalid Value***********************");logger.Debug("***********File Name="+fileName);logger.Debug("***********File Path="+filePath);fileName = fileName.Clean();logger.Debug("*********替换过后的File Name************************************");logger.Debug(fileName);}if (fileName.StartsWith(".") || fileName.EndsWith(".")){fileName=fileName.Replace(".", "-");}//判断文件是否已经存在,若存在,则不再重复上传string spFileUrl = spFolderUrl + "/" + fileName;SPFile newSpFile = currentWeb.GetFile(spFileUrl);if (!newSpFile.Exists){using (FileStream fs = File.OpenRead(filePath)){byte[] contentBytes = new byte[fs.Length];fs.Read(contentBytes, 0, (int)fs.Length);if (newFolder != null){SPFile spFile = newFolder.Files.Add(fileName, contentBytes, true);newFolder.Update();}}logger.Debug(fileName + "上传成功 and FilePath=" + filePath);}else{logger.Debug(spFileUrl+"已存在");}}catch (Exception ex){logger.Debug(ex.ToString());throw;}}

三、异常处理

主要发生的异常是文件名包含Invalid字符,对SharePoint而言,文档库Folder和File的名字都有严格的限制,不能包含#、%等,现在处理异常是记录到日志然后手动去修改名称

  • 报错的异常

  • 将异常记录至日志里,方便修改。

四、检查是否导入成功

  • 导入成功界面

  • 检查日志

  • 登陆系统,检查是否全部导入,并且检查权限设置是否正确。

  • 查看文件夹和文档是否成功创建和上传

转载于:https://my.oschina.net/OceanEyes/blog/381462

迁移TFS,批量将文档导入SharePoint 2013 文档库相关推荐

  1. SharePoint 2013 文档库中PPT转换PDF

    SharePoint 2013 文档库中PPT转换PDF 原文:SharePoint 2013 文档库中PPT转换PDF 通过使用 PowerPoint Automation Services,可以从 ...

  2. sharepoint 2013 文档库eventhandle权限控制

    记录一下如何在sharepoint server 2013文档库中,使用eventhandle控制文档库document library的条目item权限. ///<summary> // ...

  3. sharepoint 2013 文档库 资源管理器打开报错 在文件资源管理器中打开此位置时遇到问题,将此网站添加到受信任站点列表,然后重试。

    我们在使用sharepoint 2013的文档库或者资源库的时候,经常会需要用到使用"资源管理器"来管理文档,但是有时候,点击"使用资源管理器打开",会提示如下 ...

  4. sharepoint搭建文档服务器,SharePoint 2013 安装和配置概述

    SharePoint 2013 安装和配置概述 03/21/2018 本文内容 **上一次修改主题:**2017-08-23 **摘要:**了解如何在场中安装和配置 SharePoint Server ...

  5. sharepoint 2013文档上传最大50M怎么改啊

    当您尝试将一个大文件上载到 Windows SharePoint Services 3.0 站点上的文档库可能出现:"请求超时"错误 原因  如果您尝试上载的文件大小超过 50 兆 ...

  6. SharePoint 2013 文档库“样式”变了

    有朋友反馈说文档库的样式变了. 经查证,原来有人修改了视图的"样式":库设置-视图-样式,改为默认即可. 另外,如果编辑页面,编辑web部件的属性,在"杂项"勾 ...

  7. SharePoint 2013 入门教程--系列文章

    转:http://www.cnblogs.com/jianyus/p/3381415.html 以下文章是自己在学习SharePoint的过程中,不断积累和总结的博文,现在总结一个目录,分享给大家.这 ...

  8. SharePoint 2013 入门教程

    SharePoint 2013 入门教程 以下文章是自己在学习SharePoint的过程中,不断积累和总结的博文,现在总结一个目录,分享给大家.这个博客也是自己从SharePoint入门,到一个Sha ...

  9. SharePoint 2010文档库批量下载文档的实现

    在SharePoint 2010文档库中,结合单选框,在Ribbon中提供了批量处理文档的功能,比如,批量删除.批量签出.批量签入等,但是,很遗憾,没有提供批量下载,如图: 若选中多个文档后,会发现D ...

最新文章

  1. 报错解决:alueError: When using data tensors as input to a model, you should specify the `steps_per_epoch
  2. 一图弄懂ARM中都有什么
  3. sqlalchemy如何实现时间列自动更新?
  4. python数据科学-多变量数据分析
  5. 前端学习(2015)vue之电商管理系统电商系统之实现图片的预览效果
  6. 30个值得关注的Vue开源项目
  7. 狗屎的Easy UI ,链接页面出错!搞了我一上午!
  8. 后台管理软件测试用例,如何进行测试用例管理?
  9. java通用排序工具类
  10. 近几年热门的计算机专业,中国近十年最受高考状元青睐专业排行榜
  11. Tif格式图片的读取与保存
  12. c语言求数组交集并集差集,求两个数组的交集、并集和差集算法分析与实现
  13. java标签用setbounds,java-摆动setResizable和setBounds
  14. python接受键盘输入_Python读取键盘输入的2种方法
  15. 前端和后端到底有什么区别?待遇和前景如何?
  16. 基于Linux的socket网络编程项目——游侠手机商城
  17. 网页功能升华必备播放器
  18. 《Windows办公指南》魔改C:\Windows\System32\drivers\etc\hosts实现一个数据中心
  19. MySql计算两个日期的时间差函数
  20. ORB-SLAM2系列第六章—— 跟踪线程

热门文章

  1. 使用MATLAB快速提取图片数据
  2. [量化-034]金融哲学-道德经解读-005-“道”是什么
  3. 大学生计算机入学考试试题,大学生统考计算机一级考试试题题库.doc
  4. Fiddler抓包夜神模拟器
  5. 夜神模拟器——vscode调试模拟器找不到模拟器
  6. 2021年全球探针卡收入大约2506.3百万美元,预计2028年达到3823.8百万美元,2022至2028期间,年复合增长率CAGR为 6.2%
  7. 重磅!大数据《实战全栈工程师成长手册》,附 PDF PPT 下载
  8. [iPhone]解决:手指按住不动时,屏幕也会上下抖动
  9. Apache ShardingSphere 一文读懂
  10. 将SSH多次登录失败的IP加入黑名单