寫在前
之前寫了一篇關於 資料夾與檔案的操作的文章 操作檔案方法簡單總結(File,Directory,StreamReader,StreamWrite )
把常用的對於檔案與資料夾的操作總結了一下,在文章的回覆中有提到 遺漏的方法,並建議做一個文件管理工具 ,一細想是可以啊,之後就開始構思,最後大至需求如下,
因為都是下班後在家中花時間做的,時間有點短,有BUG是正常的,希望大家諒解,再一個對windows的檔案許可權,幾乎是0接觸所以把許可權處理留到了後期,如果大家有關於資料夾許可權處理的好文章,希望大家給我留言,好的東西需要分享,本篇會寫一下幾個功能點的思路與做法,算是對自己的總結,如果對本專案有興趣的朋友請 狂點這裡
最後如果您覺得,有什麼地方做得不夠好,或者您有什麼建議 與 意見 請一定要指出! 在此非常感謝!
一 工具功能點
二 工具基本介紹
三 功能實現講解
1 public class zTreeModel 2 { 3 public zTreeModel() 4 { 5 _isPrent = false; 6 _children = new List<zTreeModel>(); 7 } 8 9 private bool _isPrent ; 10 private List<zTreeModel> _children = null; 11 12 /// <summary> 13 ///根結點名字 14 /// </summary> 15 public string rootFullName { get; set; } 16 17 /// <summary> 18 /// 父結點名稱 19 /// </summary> 20 public string pName { get; set; } 21 /// <summary> 22 /// 父結點全路徑名稱 23 /// </summary> 24 public string pFullName { get; set; } 25 26 /// <summary> 27 /// 當前結點全路徑名稱 28 /// </summary> 29 public string fullName { get; set; } 30 31 /// <summary> 32 /// 當前結點名稱 33 /// </summary> 34 public string name { get; set; } 35 36 /// <summary> 37 /// 是否為父結點 38 /// </summary> 39 public bool isParent { 40 get { return _isPrent; } 41 set { _isPrent = value; } 42 } 43 /// <summary> 44 /// 是否為頂層節點 45 /// </summary> 46 public bool topNode { get; set; } 47 48 /// <summary> 49 /// 是否為檔案 預設為False 50 /// </summary> 51 public bool isFile { get; set; } 52 53 /// <summary> 54 /// 是否開啟 55 /// </summary> 56 public bool open { get; set; } 57 58 /// <summary> 59 /// 子結點 60 /// </summary> 61 public List<zTreeModel> children 62 { 63 get { return _children; } 64 set { _children = value; } 65 } 66 }
JavaScript
1 var zTreeObj, 2 setting = { 3 view: { 4 selectedMulti: true, 5 showLine: true 6 }, 7 edit: { 8 drag: { 9 isMove: true, 10 inner:true//拖拽後為同級節點, 11 },//託拽操作配置 12 enable: true,//節點可編輯 13 showRemoveBtn: false, 14 showRenameBtn: false, 15 editNameSelectAll: true 16 }, 17 data: { 18 keep: { 19 parent:true //刪除子節點後父節點不變為葉子節點 20 }, 21 22 }, 23 async: { 24 enable: true, 25 autoParam:["fullName"], 26 url: "/FileManager/GetSingleLevelNodes", 27 type: "POST", 28 29 }, 30 treeNode: { 31 checked:true 32 33 }, 34 callback: 35 { 36 // beforeExpand: zTreeBeforeExpand,//展開節點前的回撥方法 37 38 beforeRename: zTreeBeforeRename,//重新命名之前的回撥方法 39 onRename: zTreeOnRename,//重新命名 40 41 beforeRemove: zTreeBeforeRemove,//刪除前回撥方法 42 onRemove: zTreeRemove,//刪除 43 44 beforeRightClick: zTreeBeforeRightClick,//右鍵方法前的回撥 45 onRightClick: zTreeOnRightClick,//右鍵方法 46 47 beforeDrop: zTreeBeforeDrop,//用於捕獲節點拖拽操作結束之前的事件回撥函式,並且根據返回值確定是否允許此拖拽操作.如果返回 false,zTree 將恢復被拖拽的節點,也無法觸發 onDrop 事件回撥函式 48 onDrop: zTreeOnDrop,//拖拽操作結束的事件 49 beforeDrag: zTreeBeforeDrag//託拽前的方法 50 51 } 52 }; 53 54 var zTreeNodes = ""; 55 $(function () { 56 ReLoadTree(); 57 }); 58 59 function ReLoadTree() { 60 $.ajax({ 61 url: "/FileManager/GetDefaultFiles", 62 type: "POST", 63 async: false, 64 dataType: "json", 65 success: function (data) { 66 zTreeNodes = data; 67 } 68 }); 69 zTreeObj = $.fn.zTree.init($("#tree"), setting, zTreeNodes); 70 71 }
C#
1 public List<zTreeModel> GetDefaultFiles(string path) 2 { 3 zTreeModel treeModel = null; 4 List<zTreeModel> treeModelList = new List<zTreeModel>(); 5 if (Directory.Exists(path)) 6 { 7 //獲取子目錄 8 DirectoryInfo directory = new DirectoryInfo(path); 9 10 try 11 { 12 var folders = directory.GetDirectories(); 13 //遍歷路徑下資料夾 14 foreach (var folder in folders) 15 { 16 treeModel = new zTreeModel(); 17 treeModel.pName = folder.Parent == null ? " " : folder.Parent.Name; 18 treeModel.pFullName = folder.Parent == null ? " " : folder.Parent.FullName; 19 treeModel.rootFullName = folder.Root.FullName; 20 treeModel.name = folder.Name; 21 treeModel.fullName = folder.FullName; 22 treeModel.isParent = true; 23 treeModelList.Add(treeModel); 24 } 25 26 } 27 catch (UnauthorizedAccessException ex)//呼叫方沒有所要求的許可權。 28 { 29 return null; 30 } 31 32 //獲取路徑下檔案 33 DirectoryInfo fileDirectory = new DirectoryInfo(path); 34 35 try 36 { 37 var files = fileDirectory.GetFiles(); 38 foreach (var file in files) 39 { 40 treeModel = new zTreeModel(); 41 treeModel.pName = file.Directory == null ? "" : file.Directory.Name; 42 treeModel.pFullName = file.DirectoryName; 43 treeModel.rootFullName = file.Directory == null ? "" : file.Directory.Root.FullName; 44 treeModel.name = file.Name; 45 treeModel.fullName = file.FullName; 46 treeModel.isFile = true; 47 treeModelList.Add((treeModel)); 48 } 49 50 } 51 catch (UnauthorizedAccessException ex) //呼叫方沒有所要求的許可權。 52 { 53 return null; 54 } 55 } 56 57 return treeModelList; 58 59 }
3.2 新增資料夾節點
實現思路:彈出框寫資料夾名,然後前臺組裝新節點的json資料,並把新節點物件傳到Action中反序列化成物件,根據節點屬性建立資料夾,如果已存在相同檔名則提示,否則正常建立
javascript
1 //新增節點 2 function zTreeAddNode() { 3 var zTreeObj = $.fn.zTree.getZTreeObj("tree"); 4 var parent = zTreeObj.getSelectedNodes()[0]; //把選中的節點當做父節點 5 if (parent == undefined) { 6 layer.alert('給新孩子找個父節點啊~~', 8); 7 return false; 8 } else if (parent.isParent == false) { 9 layer.alert('親~只能選資料夾哦~', 8); 10 return false; 11 } 12 13 ShowDialog(parent, zTreeObj); 14 } 15 16 function ShowDialog(parent, zTreeObj) { 17 18 $.layer({ 19 shade: [0.5, '#000', true], //遮罩 20 dialog: { 21 msg: '資料夾名:<input type="text" id="folderName"/>', 22 title: ['新建資料夾', true], 23 btns: 2, 24 type: 1, 25 area: ['503px', '395px'], 26 btn: ['新增', '取消'], 27 yes: function(index) { 28 29 var name = $("#folderName").val(); 30 if (name == "") { 31 layer.alert('啊喂~還沒寫名字呢~', 8); 32 return false; 33 } 34 //拼裝新節點物件 35 var nodes = { "fullName": parent.fullName + " \\ " + name, "name": name, "pName": parent.pName, "pFullName": parent.pFullName, "isParent": true }; 36 $.ajax({ 37 url: "/FileManager/AddNode", 38 type: "POST", 39 data: { 40 "node": JSON.stringify(nodes) 41 }, 42 dataType: "json", 43 success: function(data) { 44 if (!data.Status) { 45 layer.alert(data.Message, 8); 46 layer.close(index); 47 return false; 48 } 49 zTreeObj.addNodes(parent, nodes); 50 layer.close(index); 51 } 52 }); 53 54 }, 55 no: function(index) { 56 layer.close(index); 57 } 58 } 59 }); 60 61 }
C#
1 public OperationResult CreateFolder(zTreeModel zTree, OperationResult operation) 2 { 3 DirectoryInfo directory = new DirectoryInfo(zTree.fullName); 4 if (directory.Exists) 5 { 6 operation.Status = false; 7 operation.Message = "資料夾已存在了哦~"; 8 } 9 else 10 { 11 directory.Create(); 12 } 13 return operation; 14 }
3.3 刪除樹上資料夾節點
思路:取到選中節點,再取節點fullName 屬性,(此屬性儲存了檔案的全路徑),把fullName非同步傳入Action後呼叫方法,遞迴刪除資料夾,遞迴的方式是先遍歷到最深層的子資料夾如果有遇到不可訪問的檔案則刪除操作不能繼續進行,並提示使用者不能刪除的資料夾名,如果都可訪問則從最深層的子資料夾開始遞迴刪除,程式碼如下
JavaScript
1 //刪除節點 2 function zTreeRemove() { 3 var treeObj = $.fn.zTree.getZTreeObj("tree"); 4 var node = treeObj.getSelectedNodes(); 5 var isParents = false; 6 $.each(node, function(index, item) { 7 if (item.isParent) { 8 isParents = true; 9 } 10 }); 11 if (isParents) { 12 var meg = "確定要把資料夾中所有檔案都刪了嗎?不能恢復的哦~也不能怪我哦~"; 13 deleteNodes(node, meg); 14 } else { 15 var meg = "確定要刪除所以選中的檔案嗎?不能恢復的哦~"; 16 deleteNodes(node, meg); 17 } 18 } 19 function deleteNodes(nodes, meg) { 20 $.layer({ 21 shade: [0.5, '#000', true], //遮罩 22 dialog: { 23 msg: meg, 24 title: '刪除資料夾', 25 btns: 2, 26 type: 1, 27 area: ['503px', '395px'], 28 btn: ['刪除', '取消'], 29 yes: function(index) { 30 $.ajax({ 31 url: "/FileManager/DeleteNode", 32 type: "POST", 33 data: { "node": JSON.stringify(nodes) }, 34 dataType: "json", 35 success: function(data) { 36 if (!data.Status) { 37 layer.alert(data.Message, 8); 38 } else { 39 var treeObj = $.fn.zTree.getZTreeObj("tree"); 40 var selectedNodes = treeObj.getSelectedNodes(); 41 for (var i = 0; i < selectedNodes.length; i++) { 42 treeObj.removeNode(selectedNodes[i]); 43 } 44 } 45 } 46 }); 47 layer.close(index); 48 }, no: function(index) { 49 layer.close(index); 50 } 51 } 52 53 }); 54 55 }
C#
1 public OperationResult Delete(DirectoryInfo directory, OperationResult operation) 2 { 3 //從深層子目錄開始遍歷刪除 4 DirectoryInfo[] childFolder = directory.GetDirectories(); 5 6 if (operation.Status) 7 { 8 //有元素就遍歷刪除,沒有則直接刪除資料夾 9 if (childFolder.Any()) 10 { 11 foreach (var directoryInfo in childFolder) 12 { 13 Delete(directoryInfo, operation); 14 FileInfo[] files = directoryInfo.GetFiles(); 15 try 16 { 17 foreach (var fileInfo in files) 18 { 19 fileInfo.Delete(); 20 } 21 directoryInfo.Delete(); 22 } 23 catch (UnauthorizedAccessException ex) 24 { 25 operation.Status = false; 26 operation.Message = string.Format("{0}此資料夾沒有許可權訪問!無法執行刪除操作", directoryInfo.FullName); 27 return operation; 28 } 29 } 30 } 31 else 32 { 33 //驗證檔案是否能刪除 34 try 35 { 36 directory.Delete(); 37 } 38 catch (UnauthorizedAccessException ex) 39 { 40 operation.Status = false; 41 operation.Message = string.Format("{0}此資料夾沒有許可權訪問!無法執行刪除操作", directory.FullName); 42 return operation; 43 } 44 } 45 } 46 return operation; 47 }
3.4 右鍵方法
思路:點選右鍵時觸發右鍵事件,在事件方法中把事先寫好的Html選單展示出來並繫結相應的js事件,根結點沒有刪除與重新命名操作,只能新增子節點
javaScript
1 //右鍵方法 2 function zTreeOnRightClick(event, treeId, treeNode) { 3 if (treeId == undefined) { 4 return false; 5 } 6 7 $("#rMenu").css({ 8 top: event.clientY + "px", 9 left:event.clientX +"px", 10 display: "block", 11 "z-index": 1 12 }); 13 14 if (treeNode.topNode) { 15 showItem(["#addFolder"]); 16 } else { 17 showItem(["#addFolder", "#reName", "#deleteFile"]); 18 } 19 20 } 21 //顯示右鍵選單 22 function showItem(itemArray) { 23 24 for (var i = 0; i < itemArray.length; i++) { 25 26 $(itemArray[i]).show(); 27 } 28 $("#rMenu").hover(function() { 29 $("#addFolder").click(function() { 30 //alert("第一次新增!"); 31 zTreeAddNode(); 32 $("#rMenu").hide(); 33 }); 34 $("#reName").click(function() { 35 Rename(); 36 $("#rMenu").hide(); 37 }); 38 $("#deleteFile").click(function() { 39 zTreeRemove(); 40 $("#rMenu").hide(); 41 }); 42 }, 43 function() { 44 for (var j = 0; j < itemArray.length; j++) { 45 $(itemArray[j]).hide(); 46 } 47 }); 48 49 }
3.5 重新命名
思路:觸發重新命名方法後會使節點處於編輯狀態,失去焦點後自動儲存,在儲存時先要做驗證沒有相同的檔名,並重新整理節點的屬性
注意:因為要先驗證檔名是否已存在,所以先要非同步去檢查,但是檢查與執行重新命名的方法都是非同步的沒法分先後,且方法都要用的zTree提供的方法,所以每次重新命名後要重新載入一次整棵樹 體驗有點不太好
javascript
1 function zTreeBeforeRename(treeId, treeNode, newName, isCancel) { 2 //檔名長度不能超過260個字元(包括路徑) 3 var zTreeObj = $.fn.zTree.getZTreeObj("tree"); 4 if ((treeNode.fullName + newName).length > 260) { 5 layer.alert("啊喂~ 你檔名也太長了點吧!", 8); 6 zTreeObj.editName(treeNode); 7 } 8 var status = false; 9 var path = treeNode.pFullName + "\\" + newName; 10 //判斷新檔名是否已存在 11 $.ajax({ 12 url: "/FileManager/CheckRename", 13 async:false, 14 type: "POST", 15 data: { 16 "path": path, 17 "isParent": treeNode.isParent 18 }, 19 dataType: "json", 20 success: function (data) { 21 status = data.Status; 22 if (!data.Status) { 23 layer.alert(data.Message, 8); 24 //阻止因Alter反覆呼叫zTreeBeforeRename方法 25 //zTreeObj.editName(treeNode); 26 //return false; 27 } else { 28 //return true; 29 } 30 } 31 }); 32 33 if (status) { 34 return true; 35 } else { 36 return false; 37 } 38 39 } 40 41 function Rename() { 42 var zTreeObj = $.fn.zTree.getZTreeObj("tree"); 43 var nodes = zTreeObj.getSelectedNodes();//取到為選中節點陣列 44 zTreeObj.editName(nodes[0]);//把第一個節點變為編輯狀態 45 46 } 47 48 //重新命名 49 function zTreeOnRename(event, treeId, treeNode, isCancel) { 50 51 //把檢查檔名放在此方法中 52 53 var zTreeObj = $.fn.zTree.getZTreeObj("tree"); 54 55 var path = treeNode.fullName; 56 var destPath = treeNode.pFullName + "\\" + treeNode.name; 57 var isParent = treeNode.isParent; 58 //重新命名後,fullname,name 都要修改 59 $.ajax({ 60 url: "/FileManager/RenameFiles", 61 async:false, 62 type: "POST", 63 data: { 64 "path": path, 65 "destPath": destPath, 66 "isParent": isParent 67 }, 68 dataType: "json", 69 success: function(data) { 70 if (data.Status) { 71 72 ReLoadTree(); 73 74 //重新命名後重新整理父節點,更新子節點中的fullName等屬性 75 //var selectNodes = zTreeObj.getSelectedNodes(); 76 //var parent = selectNodes[0].getParentNode(); 77 //zTreeObj.reAsyncChildNodes(parent, "refresh"); 78 } 79 } 80 }); 81 82 83 }
C#
1 //檢查檔名是否存在 2 public void CheckFileName(string path, bool isParent,OperationResult operation) 3 { 4 if (isParent) 5 { 6 if (Directory.Exists(path)) 7 { 8 operation.Status = false; 9 operation.Message = "資料夾已經存在了哦!"; 10 } 11 } 12 else 13 { 14 if (File.Exists(path)) 15 { 16 operation.Status = false; 17 operation.Message = "檔案已經存在了哦!"; 18 } 19 } 20 } 21 //重新命名 22 public void RenameFileName(string path, string destPath, bool isParent, OperationResult operation) 23 { 24 if (isParent) 25 { 26 DirectoryInfo directory = new DirectoryInfo(path); 27 directory.MoveTo(destPath); 28 } 29 else 30 { 31 FileInfo file = new FileInfo(path); 32 file.MoveTo(destPath); 33 } 34 }
3.6 拖拽方法(移動資料夾,按Ctrl可多選)
思路:根節點不能被拖動,也不能拖為根節點,然後遍歷選中的節點,並傳到Action中反序列化成物件執行移動,並在移動後在前端把節點的屬性pName fullName pFullName更新,避免重新載入樹
javascript
1 //拖拽前的方法 2 function zTreeBeforeDrag(treeId, treeNodes) { 3 //根結點不能被移動, 4 for (var i = 0; i < treeNodes.length; i++) { 5 if (treeNodes[i].topNode) { 6 layer.alert("根結點不能被託動哦~", 8); 7 return false; 8 } 9 } 10 } 11 //捕獲節點拖拽操作結束之前的事件回撥函式,並且根據返回值確定是否允許此拖拽操作 12 //如果返回 false,zTree 將恢復被拖拽的節點,也無法觸發 onDrop 事件回撥函式 13 14 function zTreeBeforeDrop(treeId, treeNodes, targetNode, moveType) { 15 //不能拖拽為根節點 16 if ((targetNode == null || (moveType != "inner"))) { 17 return false; 18 } 19 if (!targetNode.isParent) { 20 layer.alert("只能託動到資料夾內哦~", 8); 21 return false; 22 } 23 24 $.ajax({ 25 url: "FileManager/MoveFiles", 26 async: false, 27 type: "POST", 28 data: { 29 "nodes": JSON.stringify(treeNodes), 30 "targetNode": JSON.stringify(targetNode) 31 }, 32 dataType: "json", 33 success: function (data) { 34 if (!data.Status) { 35 layer.alert(data.Message, 8); 36 return false; 37 } else { 38 //節點拖動後要把的路徑改為新路徑 39 for (var i = 0; i < treeNodes.length; i++) { 40 treeNodes[i].fullName = targetNode.fullName + "\\" + treeNodes[i].name; 41 treeNodes[i].pName = targetNode.name; 42 treeNodes[i].pFullName = targetNode.fullName; 43 } 44 } 45 } 46 }); 47 }
C#
1 public void MoveFilesToFolder(List<zTreeModel> nodes, zTreeModel targetNode,OperationResult operation) 2 { 3 4 5 foreach (var node in nodes) 6 { 7 //資料夾 8 if (node.isParent) 9 { 10 DirectoryInfo directory = new DirectoryInfo(node.fullName); 11 if (Directory.Exists(targetNode.fullName)) 12 { 13 //要移動的新地址 14 string newPath = targetNode.fullName + "\\" + node.name; 15 directory.MoveTo(newPath); 16 } 17 else 18 { 19 operation.Status = false; 20 operation.Message = string.Format("{0}資料夾不存在啊~!", node.fullName); 21 } 22 23 }//檔案 24 else 25 { 26 FileInfo file = new FileInfo(node.fullName); 27 if (Directory.Exists(targetNode.fullName)) 28 { 29 string newPath = targetNode.fullName + "\\" + node.name; 30 file.MoveTo(newPath); 31 } 32 else 33 { 34 operation.Status = false; 35 operation.Message = string.Format("{0}資料夾不存在啊~!", node.fullName); 36 } 37 } 38 39 } 40 41 }
四 總結
雖然這個小工具功能並不強大,但至少是我從有想法到有行動到有成果的一個過程,並且我也享受這一過程,
在開發的過程中,瞭解了zTree的各種用法,對資料夾,檔案的操作也有了更深入的瞭解,
如果您覺得這個工具有那麼點意思 不妨點下推薦哦~您的推薦是我創作源源不斷的動力