文件夹管理工具(MVC+zTree+layer)(附源码)

 

写在前

之前写了一篇关于 文件夹与文件的操作的文章  操作文件方法简单总结(File,Directory,StreamReader,StreamWrite ) 

把常用的对于文件与文件夹的操作总结了一下,在文章的回复中有提到 遗漏的方法,并建议做一个文档管理工具 ,一细想是可以啊,之后就开始构思,最后大至需求如下,

因为都是下班后在家中花时间做的,时间有点短,有BUG是正常的,希望大家谅解,再一个对windows的文件权限,几乎是0接触所以把权限处理留到了后期,如果大家有关于文件夹权限处理的好文章,希望大家给我留言,好的东西需要分享,本篇会写一下几个功能点的思路与做法,算是对自己的总结,如果对本项目有兴趣的朋友请 狂点这里

最后如果您觉得,有什么地方做得不够好,或者您有什么建议 与 意见 请一定要指出! 在此非常感谢!

一 工具功能点

 一 展示
1 以树形展示单个磁盘内所有文件夹子文件夹,与文件名
2 支持子文件夹的层级展开
3 右侧支持文本文档的预览(二期)
4 若是图片支持预览(二期)
 
二 操作
 1 支持指定目录下的文件夹新增,(右键)
 2 支持指定目录下的文件夹删除(右键)
 3 支持指定目录下的文件夹,与文件的重命名((右键))
 4 支持指定目录下的文件夹与文件移动到另一指定的文件夹(托拽)
 5 支持指定目录下的文件夹批量删除
 6 支持指定目录下的文件搜索 (只要文件名匹配即可)(二期)
 7 文件夹与文件的访问权限处理
 
以上就是大至简单的需求,然后根据需求,选择了以下几个小插件
zTree:树形插件 个人觉得很不错,国内的插件,API文档解释很详细,至少我从来没用过树形插件的,比较容易的就上手了。 zTree插件地址
Layer:弹出层插件,使用简单,效果好,拿来即用 Layer插件地址
 

二 工具基本介绍

 
先上几张图  新建文件夹,文件夹或文件重命名
         
 
删除文件或文件夹(支持批量删除)
 
 
以拖拽形式批量移动文件夹
 
 
 
 

三 功能实现讲解

 
3.1 加载文件夹树
 
  根据zTree需要的参数配置就行了,具体参数请大家看zTree的API吧,着重写一下加载时遇到的坑
实现思路:遍历指定路径下第一层所有文件夹与文件并组成对象序列化成Json并返回Json数据给zTree绑定
 
    刚开始想着一次性把所有的文件与文件夹都加载出来,然后用递归实现,但是因为我定义了一个类来保存文件的信息,而且是以嵌套的形式存的,这样的做法初看觉得
很有层次感到写递归时,却把自己坑了,也主要是以前没认真写过递归,导致这一方法纠结了一个晚上再加上午的一点时间,终于递归出来了,
然后一试验,浏览器直接死了,数量太大嵌套的太深,加载一次至少要40秒以上,于是果断放弃了,改为每次只加载一层
以下为保存数据的类,与加载的方法 , 这里只列出部分代码,具体代码在源码中都可找到
 
类设计
 
public class zTreeModel
{
public zTreeModel()
{
_isPrent = false;
_children = new List<zTreeModel>();
}
private bool _isPrent ;
private List<zTreeModel> _children = null; /// <summary>
///根结点名字
/// </summary>
public string rootFullName { get; set; }
/// <summary>
/// 父结点名称
/// </summary>
public string pName { get; set; }
/// <summary>
/// 父结点全路径名称
/// </summary>
public string pFullName { get; set; }
/// <summary>
/// 当前结点全路径名称
/// </summary>
public string fullName { get; set; }
/// <summary>
/// 当前结点名称
/// </summary>
public string name { get; set; } /// <summary>
/// 是否为父结点
/// </summary>
public bool isParent {
get { return _isPrent; }
set { _isPrent = value; }
}
/// <summary>
/// 是否为顶层节点
/// </summary>
public bool topNode { get; set; }
/// <summary>
/// 是否为文件 默认为False
/// </summary>
public bool isFile { get; set; }
/// <summary>
/// 是否打开
/// </summary>
public bool open { get; set; }
/// <summary>
/// 子结点
/// </summary>
public List<zTreeModel> children
{
get { return _children; }
set { _children = value; }
}
}

JavaScript

 
var zTreeObj,
setting = {
view: {
selectedMulti: true,
showLine: true
},
edit: {
drag: {
isMove: true,
inner:true//拖拽后为同级节点,
},//托拽操作配置
enable: true,//节点可编辑
showRemoveBtn: false,
showRenameBtn: false,
editNameSelectAll: true
},
data: {
keep: {
parent:true //删除子节点后父节点不变为叶子节点
}, },
async: {
enable: true,
autoParam:["fullName"],
url: "/FileManager/GetSingleLevelNodes",
type: "POST", },
treeNode: {
checked:true },
callback:
{
// beforeExpand: zTreeBeforeExpand,//展开节点前的回调方法
beforeRename: zTreeBeforeRename,//重命名之前的回调方法
onRename: zTreeOnRename,//重命名 beforeRemove: zTreeBeforeRemove,//删除前回调方法
onRemove: zTreeRemove,//删除 beforeRightClick: zTreeBeforeRightClick,//右键方法前的回调
onRightClick: zTreeOnRightClick,//右键方法 beforeDrop: zTreeBeforeDrop,//用于捕获节点拖拽操作结束之前的事件回调函数,并且根据返回值确定是否允许此拖拽操作.如果返回 false,zTree 将恢复被拖拽的节点,也无法触发 onDrop 事件回调函数
onDrop: zTreeOnDrop,//拖拽操作结束的事件
beforeDrag: zTreeBeforeDrag//托拽前的方法 }
}; var zTreeNodes = "";
$(function () {
ReLoadTree();
}); function ReLoadTree() {
$.ajax({
url: "/FileManager/GetDefaultFiles",
type: "POST",
async: false,
dataType: "json",
success: function (data) {
zTreeNodes = data;
}
});
zTreeObj = $.fn.zTree.init($("#tree"), setting, zTreeNodes);
}

C#

 
public List<zTreeModel> GetDefaultFiles(string path)
{
zTreeModel treeModel = null;
List<zTreeModel> treeModelList = new List<zTreeModel>();
if (Directory.Exists(path))
{
//获取子目录
DirectoryInfo directory = new DirectoryInfo(path); try
{
var folders = directory.GetDirectories();
//遍历路径下文件夹
foreach (var folder in folders)
{
treeModel = new zTreeModel();
treeModel.pName = folder.Parent == null ? " " : folder.Parent.Name;
treeModel.pFullName = folder.Parent == null ? " " : folder.Parent.FullName;
treeModel.rootFullName = folder.Root.FullName;
treeModel.name = folder.Name;
treeModel.fullName = folder.FullName;
treeModel.isParent = true;
treeModelList.Add(treeModel);
}
}
catch (UnauthorizedAccessException ex)//调用方没有所要求的权限。
{
return null;
}
//获取路径下文件
DirectoryInfo fileDirectory = new DirectoryInfo(path); try
{
var files = fileDirectory.GetFiles();
foreach (var file in files)
{
treeModel = new zTreeModel();
treeModel.pName = file.Directory == null ? "" : file.Directory.Name;
treeModel.pFullName = file.DirectoryName;
treeModel.rootFullName = file.Directory == null ? "" : file.Directory.Root.FullName;
treeModel.name = file.Name;
treeModel.fullName = file.FullName;
treeModel.isFile = true;
treeModelList.Add((treeModel));
}
}
catch (UnauthorizedAccessException ex) //调用方没有所要求的权限。
{
return null;
}
}
return treeModelList;
}

3.2 新增文件夹节点

实现思路:弹出框写文件夹名,然后前台组装新节点的json数据,并把新节点对象传到Action中反序列化成对象,根据节点属性创建文件夹,如果已存在相同文件名则提示,否则正常创建

javascript

 
//新增节点
function zTreeAddNode() {
var zTreeObj = $.fn.zTree.getZTreeObj("tree");
var parent = zTreeObj.getSelectedNodes()[0]; //把选中的节点当做父节点
if (parent == undefined) {
layer.alert('给新孩子找个父节点啊~~', 8);
return false;
} else if (parent.isParent == false) {
layer.alert('亲~只能选文件夹哦~', 8);
return false;
}
ShowDialog(parent, zTreeObj);
}
function ShowDialog(parent, zTreeObj) {
$.layer({
shade: [0.5, '#000', true], //遮罩
dialog: {
msg: '文件夹名:<input type="text" id="folderName"/>',
title: ['新建文件夹', true],
btns: 2,
type: 1,
area: ['503px', '395px'],
btn: ['添加', '取消'],
yes: function(index) { var name = $("#folderName").val();
if (name == "") {
layer.alert('啊喂~还没写名字呢~', 8);
return false;
}
//拼装新节点对象
var nodes = { "fullName": parent.fullName + " \\ " + name, "name": name, "pName": parent.pName, "pFullName": parent.pFullName, "isParent": true };
$.ajax({
url: "/FileManager/AddNode",
type: "POST",
data: {
"node": JSON.stringify(nodes)
},
dataType: "json",
success: function(data) {
if (!data.Status) {
layer.alert(data.Message, 8);
layer.close(index);
return false;
}
zTreeObj.addNodes(parent, nodes);
layer.close(index);
}
});
},
no: function(index) {
layer.close(index);
}
}
});
}

C#

 
public OperationResult CreateFolder(zTreeModel zTree, OperationResult operation)
{
DirectoryInfo directory = new DirectoryInfo(zTree.fullName);
if (directory.Exists)
{
operation.Status = false;
operation.Message = "文件夹已存在了哦~";
}
else
{
directory.Create();
}
return operation;
}

3.3  删除树上文件夹节点

思路:取到选中节点,再取节点fullName 属性,(此属性保存了文件的全路径),把fullName异步传入Action后调用方法,递归删除文件夹,递归的方式是先遍历到最深层的子文件夹如果有遇到不可访问的文件则删除操作不能继续进行,并提示用户不能删除的文件夹名,如果都可访问则从最深层的子文件夹开始递归删除,代码如下

JavaScript

 
//删除节点
function zTreeRemove() {
var treeObj = $.fn.zTree.getZTreeObj("tree");
var node = treeObj.getSelectedNodes();
var isParents = false;
$.each(node, function(index, item) {
if (item.isParent) {
isParents = true;
}
});
if (isParents) {
var meg = "确定要把文件夹中所有文件都删了吗?不能恢复的哦~也不能怪我哦~";
deleteNodes(node, meg);
} else {
var meg = "确定要删除所以选中的文件吗?不能恢复的哦~";
deleteNodes(node, meg);
}
}
function deleteNodes(nodes, meg) {
$.layer({
shade: [0.5, '#000', true], //遮罩
dialog: {
msg: meg,
title: '删除文件夹',
btns: 2,
type: 1,
area: ['503px', '395px'],
btn: ['删除', '取消'],
yes: function(index) {
$.ajax({
url: "/FileManager/DeleteNode",
type: "POST",
data: { "node": JSON.stringify(nodes) },
dataType: "json",
success: function(data) {
if (!data.Status) {
layer.alert(data.Message, 8);
} else {
var treeObj = $.fn.zTree.getZTreeObj("tree");
var selectedNodes = treeObj.getSelectedNodes();
for (var i = 0; i < selectedNodes.length; i++) {
treeObj.removeNode(selectedNodes[i]);
}
}
}
});
layer.close(index);
}, no: function(index) {
layer.close(index);
}
} });
}

C#

 
public OperationResult Delete(DirectoryInfo directory, OperationResult operation)
{
//从深层子目录开始遍历删除
DirectoryInfo[] childFolder = directory.GetDirectories(); if (operation.Status)
{
//有元素就遍历删除,没有则直接删除文件夹
if (childFolder.Any())
{
foreach (var directoryInfo in childFolder)
{
Delete(directoryInfo, operation);
FileInfo[] files = directoryInfo.GetFiles();
try
{
foreach (var fileInfo in files)
{
fileInfo.Delete();
}
directoryInfo.Delete();
}
catch (UnauthorizedAccessException ex)
{
operation.Status = false;
operation.Message = string.Format("{0}此文件夹没有权限访问!无法执行删除操作", directoryInfo.FullName);
return operation;
}
}
}
else
{
//验证文件是否能删除
try
{
directory.Delete();
}
catch (UnauthorizedAccessException ex)
{
operation.Status = false;
operation.Message = string.Format("{0}此文件夹没有权限访问!无法执行删除操作", directory.FullName);
return operation;
}
}
}
return operation;
}

3.4  右键方法 

思路:点击右键时触发右键事件,在事件方法中把事先写好的Html菜单展示出来并绑定相应的js事件,根结点没有删除与重命名操作,只能新增子节点

javaScript

 
//右键方法
function zTreeOnRightClick(event, treeId, treeNode) {
if (treeId == undefined) {
return false;
} $("#rMenu").css({
top: event.clientY + "px",
left:event.clientX +"px",
display: "block",
"z-index": 1
});
if (treeNode.topNode) {
showItem(["#addFolder"]);
} else {
showItem(["#addFolder", "#reName", "#deleteFile"]);
}
}
//显示右键菜单
function showItem(itemArray) { for (var i = 0; i < itemArray.length; i++) {
$(itemArray[i]).show();
}
$("#rMenu").hover(function() {
$("#addFolder").click(function() {
//alert("第一次添加!");
zTreeAddNode();
$("#rMenu").hide();
});
$("#reName").click(function() {
Rename();
$("#rMenu").hide();
});
$("#deleteFile").click(function() {
zTreeRemove();
$("#rMenu").hide();
});
},
function() {
for (var j = 0; j < itemArray.length; j++) {
$(itemArray[j]).hide();
}
});
}

3.5 重命名

思路:触发重命名方法后会使节点处于编辑状态,失去焦点后自动保存,在保存时先要做验证没有相同的文件名,并刷新节点的属性

注意:因为要先验证文件名是否已存在,所以先要异步去检查,但是检查与执行重命名的方法都是异步的没法分先后,且方法都要用的zTree提供的方法,所以每次重命名后要重新加载一次整棵树 体验有点不太好

javascript

 
function zTreeBeforeRename(treeId, treeNode, newName, isCancel) {
//文件名长度不能超过260个字符(包括路径)
var zTreeObj = $.fn.zTree.getZTreeObj("tree");
if ((treeNode.fullName + newName).length > 260) {
layer.alert("啊喂~ 你文件名也太长了点吧!", 8);
zTreeObj.editName(treeNode);
}
var status = false;
var path = treeNode.pFullName + "\\" + newName;
//判断新文件名是否已存在
$.ajax({
url: "/FileManager/CheckRename",
async:false,
type: "POST",
data: {
"path": path,
"isParent": treeNode.isParent
},
dataType: "json",
success: function (data) {
status = data.Status;
if (!data.Status) {
layer.alert(data.Message, 8);
//阻止因Alter反复调用zTreeBeforeRename方法
//zTreeObj.editName(treeNode);
//return false;
} else {
//return true;
}
}
}); if (status) {
return true;
} else {
return false;
}
}
function Rename() {
var zTreeObj = $.fn.zTree.getZTreeObj("tree");
var nodes = zTreeObj.getSelectedNodes();//取到为选中节点数组
zTreeObj.editName(nodes[0]);//把第一个节点变为编辑状态
}
//重命名
function zTreeOnRename(event, treeId, treeNode, isCancel) {
//把检查文件名放在此方法中
var zTreeObj = $.fn.zTree.getZTreeObj("tree"); var path = treeNode.fullName;
var destPath = treeNode.pFullName + "\\" + treeNode.name;
var isParent = treeNode.isParent;
//重命名后,fullname,name 都要修改
$.ajax({
url: "/FileManager/RenameFiles",
async:false,
type: "POST",
data: {
"path": path,
"destPath": destPath,
"isParent": isParent
},
dataType: "json",
success: function(data) {
if (data.Status) { ReLoadTree();
//重命名后刷新父节点,更新子节点中的fullName等属性
//var selectNodes = zTreeObj.getSelectedNodes();
//var parent = selectNodes[0].getParentNode();
//zTreeObj.reAsyncChildNodes(parent, "refresh");
}
}
}); }

C#

 
//检查文件名是否存在
public void CheckFileName(string path, bool isParent,OperationResult operation)
{
if (isParent)
{
if (Directory.Exists(path))
{
operation.Status = false;
operation.Message = "文件夹已经存在了哦!";
}
}
else
{
if (File.Exists(path))
{
operation.Status = false;
operation.Message = "文件已经存在了哦!";
}
}
}
//重命名
public void RenameFileName(string path, string destPath, bool isParent, OperationResult operation)
{
if (isParent)
{
DirectoryInfo directory = new DirectoryInfo(path);
directory.MoveTo(destPath);
}
else
{
FileInfo file = new FileInfo(path);
file.MoveTo(destPath);
}
}

3.6 拖拽方法(移动文件夹,按Ctrl可多选)

思路:根节点不能被拖动,也不能拖为根节点,然后遍历选中的节点,并传到Action中反序列化成对象执行移动,并在移动后在前端把节点的属性pName fullName pFullName更新,避免重新加载树

javascript

 
//拖拽前的方法
function zTreeBeforeDrag(treeId, treeNodes) {
//根结点不能被移动,
for (var i = 0; i < treeNodes.length; i++) {
if (treeNodes[i].topNode) {
layer.alert("根结点不能被托动哦~", 8);
return false;
}
}
}
//捕获节点拖拽操作结束之前的事件回调函数,并且根据返回值确定是否允许此拖拽操作
//如果返回 false,zTree 将恢复被拖拽的节点,也无法触发 onDrop 事件回调函数
function zTreeBeforeDrop(treeId, treeNodes, targetNode, moveType) {
//不能拖拽为根节点
if ((targetNode == null || (moveType != "inner"))) {
return false;
}
if (!targetNode.isParent) {
layer.alert("只能托动到文件夹内哦~", 8);
return false;
} $.ajax({
url: "FileManager/MoveFiles",
async: false,
type: "POST",
data: {
"nodes": JSON.stringify(treeNodes),
"targetNode": JSON.stringify(targetNode)
},
dataType: "json",
success: function (data) {
if (!data.Status) {
layer.alert(data.Message, 8);
return false;
} else {
//节点拖动后要把的路径改为新路径
for (var i = 0; i < treeNodes.length; i++) {
treeNodes[i].fullName = targetNode.fullName + "\\" + treeNodes[i].name;
treeNodes[i].pName = targetNode.name;
treeNodes[i].pFullName = targetNode.fullName;
}
}
}
});
}

C#

 
public void MoveFilesToFolder(List<zTreeModel> nodes, zTreeModel targetNode,OperationResult operation)
{ foreach (var node in nodes)
{
//文件夹
if (node.isParent)
{
DirectoryInfo directory = new DirectoryInfo(node.fullName);
if (Directory.Exists(targetNode.fullName))
{
//要移动的新地址
string newPath = targetNode.fullName + "\\" + node.name;
directory.MoveTo(newPath);
}
else
{
operation.Status = false;
operation.Message = string.Format("{0}文件夹不存在啊~!", node.fullName);
}
}//文件
else
{
FileInfo file = new FileInfo(node.fullName);
if (Directory.Exists(targetNode.fullName))
{
string newPath = targetNode.fullName + "\\" + node.name;
file.MoveTo(newPath);
}
else
{
operation.Status = false;
operation.Message = string.Format("{0}文件夹不存在啊~!", node.fullName);
}
}
} }

四 总结

虽然这个小工具功能并不强大,但至少是我从有想法到有行动到有成果的一个过程,并且我也享受这一过程,

在开发的过程中,了解了zTree的各种用法,对文件夹,文件的操作也有了更深入的了解,

如果您觉得这个工具有那么点意思 不妨点下推荐哦~您的推荐是我创作源源不断的动力

 源码在这里

 
 

文件夹管理工具(MVC+zTree+layer)的更多相关文章

  1. 文件夹管理工具(MVC+zTree+layer)(附源码)

    写在前 之前写了一篇关于 文件夹与文件的操作的文章  操作文件方法简单总结(File,Directory,StreamReader,StreamWrite )  把常用的对于文件与文件夹的操作总结了一 ...

  2. 文件和文件夹同步工具AFiles 1.0 发布

    文件和文件夹同步工具AFiles 1.0  正式发布了! 本软件支持按文件日期或长度的各种比较方式来同步文件或者文件夹. 支持双向同步功能. 支持深层文件夹功能. 可以自动产生比较和同步的记录情况. ...

  3. Java中创建操作文件和文件夹的工具类

    Java中创建操作文件和文件夹的工具类 FileUtils.java import java.io.BufferedInputStream; import java.io.BufferedOutput ...

  4. Java操作文件夹的工具类

    Java操作文件夹的工具类 import java.io.File; public class DeleteDirectory { /** * 删除单个文件 * @param fileName 要删除 ...

  5. #WEB安全基础 : HTML/CSS | 0x3文件夹管理网站

    没有头脑的管理方式会酿成大灾难,应该使用文件夹管理网站 这是一个典型的管理方法,现在传授给你,听好了 下面是0x3初识a标签里使用的网站的目录,我把它重新配置了一下

  6. 推荐一款好用的文件/文件夹对比工具 —— Beyond Compare

    推荐一款好用的文件/文件夹对比工具 —— Beyond Compare! 有需要的人,用了都说好: 不知道这个是干嘛用的,说再多也没用.

  7. linux:文件及文件夹管理

    http://blog.csdn.net/pipisorry/article/details/39854265 查看用户的信息 pika:~$id pikauid=1000(pika) gid=100 ...

  8. 文件处理工具 gif合成工具 文件后缀批量添加工具 文件夹搜索工具 重复文件查找工具 网页图片解析下载工具等

    以下都是一些简单的免费分享的工具,技术支持群:592132877,提供定制化服务开发. Gif动图合成工具 主要功能是扫描指定的文件夹里的所有zip文件,然后提取Zip文件中的图片,并合成一张gif图 ...

  9. [原创]关于在VS解决方案下使用文件夹管理多个项目层次关系的说明

    由于所创建的应用项目或类库项目较多,于是将这些类库放到一个文件夹下.在VS解决方案下确实能看到一个文件夹下多个类库项目这种层次关系.如下图所示: 但打开“我的电脑”,看到的只有类库,并未看到维护层次关 ...

随机推荐

  1. Android Studio中创建java项目

    1.创建普通的android工程 2.创建一个module 3.module类型选择java library 4.填写libary和class的名字 5.生成的工程如图所示 6.然后点击Run --- ...

  2. ServletContextListener和ContextLoaderListener的区别

    ServletContext 被 Servlet 程序用来与 Web 容器通信.例如写日志,转发请求.每一个 Web 应用程序含有一个Context,被Web应用内的各个程序共享.因为Context可 ...

  3. WPF 高性能笔

    原文:WPF 高性能笔 本文告诉大家WPF的INK的实现,和如何做一个高性能的笔. 高性能的笔迹在 WPF 包含两个部分,一个是就是输入,第二个就是渲染. 如果需要经过路由事件才收到输入,如果有人在路 ...

  4. vs中添加MySql实体集流程

    默认情况下只有下图: 首先需要下载mysql为vs和ef提供的驱动(可以去官网下载对应的版本) 然后打开vs开始添加实体类 首先在NuGet中安装MySql.Data和MySql.Data.Entit ...

  5. 桌面程序的其他实现方式----使用WPF窗体展现网页

    需求 在WPF应用程序中,需要使用到WEB项目的资源,第一时间想到的就是在WPF窗口中,展现WEB项目中的页面,这样子有两点好处:一是,实现简单,不需要在WPF应用程序中实现UI布局和数据绑定:二是, ...

  6. 配置文件——App.config文件读取和修改

    作为普通的xml文件读取的话,首先就要知道怎么寻找文件的路径.我们知道一般配置文件就在跟可执行exe文件在同一目录下,且仅仅在名称后面添加了一个.config 因此,可以用Application.Ex ...

  7. Scala & IntelliJ IDEA环境搭建升级版:在JAVA中调用Scala的helloworld

    --------------------- 前言 --------------------- 项目关系,希望用Spark GraphX做数据分析及图像展示,但前提是得会spark:spark是基于sc ...

  8. C# WPF 一直保持多个Topmost窗体的置顶顺序

    原文:C# WPF 一直保持多个Topmost窗体的置顶顺序 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37862405/article/ ...

  9. CentOS(一) 最小化安装

    /etc/sysconfig/selinux 关闭selinux /etc/sysconfig/network-scripts/网卡   设置onboot=yes service network re ...

  10. python下载图片(3)

    # -*- coding: utf-8 -*-"""some function by metaphy,2007-04-03,copyleftversion 0.2&quo ...