v9.8.2018.0605   由DataReader直接映射实体列表,以支持netstandard的MySql和SQLite,且提升性能
大石头 authored at 2018-06-05 00:45:23
12.50 KiB
X
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using XCode.Membership;

namespace NewLife.Cube.Admin.Controllers
{
    /// <summary>文件管理</summary>
    [DisplayName("文件")]
    [EntityAuthorize(PermissionFlags.Detail)]
    public class FileController : ControllerBaseX
    {
        /// <summary>菜单顺序。扫描是会反射读取</summary>
        protected static Int32 MenuOrder { get; set; }

        static FileController()
        {
            MenuOrder = 28;
        }

        #region 基础
        private String Root { get { return "../".GetFullPath(); } }

        private FileInfo GetFile(String r)
        {
            if (r.IsNullOrEmpty()) return null;

            // 默认根目录
            var fi = Root.CombinePath(r).AsFile();
            if (!fi.Exists) return null;

            return fi;
        }

        private DirectoryInfo GetDirectory(String r)
        {
            if (r.IsNullOrEmpty()) return null;

            // 默认根目录
            var di = Root.CombinePath(r).AsDirectory();
            if (!di.Exists) return null;

            return di;
        }

        //private FileSystemInfo Get(String r)
        //{
        //    var fi = GetFile(r);
        //    if (fi != null)
        //        fi.Delete();
        //    else
        //    {
        //        var di = GetDirectory(r);
        //        if (di == null) throw new Exception("找不到文件或目录!");
        //        di.Delete(true);
        //    }
        //}

        private FileItem GetItme(String r)
        {
            var inf = GetFile(r) as FileSystemInfo ?? GetDirectory(r);
            if (inf == null) return null;

            var fi = new FileItem
            {
                Name = inf.Name,
                FullName = GetFullName(inf.FullName),
                Raw = inf.FullName,
                Directory = inf is DirectoryInfo,
                LastWrite = inf.LastWriteTime
            };

            if (inf is FileInfo)
            {
                var f = inf as FileInfo;
                if (f.Length < 1024)
                    fi.Size = "{0:n0}".F(f.Length);
                else if (f.Length < 1024 * 1024)
                    fi.Size = "{0:n2}K".F((Double)f.Length / 1024);
                else if (f.Length < 1024 * 1024 * 1024)
                    fi.Size = "{0:n2}M".F((Double)f.Length / 1024 / 1024);
                else if (f.Length < 1024L * 1024 * 1024 * 1024)
                    fi.Size = "{0:n2}G".F((Double)f.Length / 1024 / 1024 / 1024);
            }

            return fi;
        }

        private String GetFullName(String r)
        {
            return r.TrimStart(Root).TrimStart(Root.TrimEnd(Path.DirectorySeparatorChar + ""));
        }
        #endregion

        #region 列表&删除
        /// <summary>文件管理主视图</summary>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Detail)]
        public ActionResult Index(String r, String sort)
        {
            var di = GetDirectory(r) ?? Root.AsDirectory();

            // 检查目录越界
            var root = Root.TrimEnd(Path.DirectorySeparatorChar);
            if (!di.FullName.StartsWithIgnoreCase(root)) di = Root.AsDirectory();

            // 计算当前路径
            var fd = di.FullName;
            if (fd.StartsWith(Root)) fd = fd.Substring(Root.Length);
            ViewBag.Current = fd;

            // 遍历所有子目录
            var fis = di.GetFileSystemInfos();
            var list = new List<FileItem>();
            foreach (var item in fis)
            {
                if (item.Attributes.Has(FileAttributes.Hidden)) continue;

                var fi = GetItme(item.FullName);

                list.Add(fi);
            }

            // 排序,目录优先
            switch (sort)
            {
                case "size":
                    list = list.OrderByDescending(e => e.Size).ThenBy(e => e.Name).ToList();
                    break;
                case "lastwrite":
                    list = list.OrderByDescending(e => e.LastWrite).ThenBy(e => e.Name).ToList();
                    break;
                case "name":
                default:
                    list = list.OrderByDescending(e => e.Directory).ThenBy(e => e.Name).ToList();
                    break;
            }
            // 在开头插入上一级目录
            if (!di.FullName.EqualIgnoreCase(Root, root))
            {
                list.Insert(0, new FileItem
                {
                    Name = "../",
                    Directory = true,
                    FullName = GetFullName(di.Parent.FullName)
                });
            }

            // 剪切板
            ViewBag.Clip = GetClip();

            return View("Index", list);
        }

        /// <summary>删除</summary>
        /// <param name="r"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Delete)]
        public ActionResult Delete(String r)
        {
            var p = "";

            var fi = GetFile(r);
            if (fi != null)
            {
                p = GetFullName(fi.Directory.FullName);
                WriteLog("删除", fi.FullName);
                fi.Delete();
            }
            else
            {
                var di = GetDirectory(r);
                if (di == null) throw new Exception("找不到文件或目录!");

                p = GetFullName(di.Parent.FullName);
                WriteLog("删除", di.FullName);
                di.Delete(true);
            }

            return RedirectToAction("Index", new { r = p });
        }
        #endregion

        #region 压缩与解压缩
        /// <summary>压缩文件</summary>
        /// <param name="r"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Insert)]
        public ActionResult Compress(String r)
        {
            var p = "";

            var fi = GetFile(r);
            if (fi != null)
            {
                p = GetFullName(fi.Directory.FullName);
                var dst = "{0}_{1:yyyyMMddHHmmss}.zip".F(fi.Name, DateTime.Now);
                dst = fi.Directory.FullName.CombinePath(dst);
                WriteLog("压缩", "{0} => {1}".F(fi.FullName, dst));
                fi.Compress(dst);
            }
            else
            {
                var di = GetDirectory(r);
                if (di == null) throw new Exception("找不到文件或目录!");

                p = GetFullName(di.Parent.FullName);
                var dst = "{0}_{1:yyyyMMddHHmmss}.zip".F(di.Name, DateTime.Now);
                dst = di.Parent.FullName.CombinePath(dst);
                WriteLog("压缩", "{0} => {1}".F(di.FullName, dst));
                di.Compress(dst);
            }

            return RedirectToAction("Index", new { r = p });
        }

        /// <summary>解压缩</summary>
        /// <param name="r"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Update)]
        public ActionResult Decompress(String r)
        {
            var fi = GetFile(r);
            if (fi == null) throw new Exception("找不到文件!");

            var p = GetFullName(fi.Directory.FullName);
            WriteLog("解压缩", fi.FullName);
            fi.Extract(fi.Directory.FullName, true);

            return RedirectToAction("Index", new { r = p });
        }
        #endregion

        #region 上传下载
        /// <summary>上传文件</summary>
        /// <param name="r"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Insert)]
        public ActionResult Upload(String r, HttpPostedFileBase file)
        {
            if (file != null)
            {
                var di = GetDirectory(r);
                if (di == null) throw new Exception("找不到目录!");

                var dest = di.FullName.CombinePath(file.FileName);
                WriteLog("上传", dest);
                file.SaveAs(dest);
            }

            return RedirectToAction("Index", new { r });
        }

        /// <summary>下载文件</summary>
        /// <param name="r"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Detail)]
        public ActionResult Download(String r)
        {
            var fi = GetFile(r);
            if (fi == null) throw new Exception("找不到文件!");

            WriteLog("下载", fi.FullName);

            return File(fi.FullName, "application/octet-stream", fi.Name);
        }
        #endregion

        #region 复制粘贴
        private const String CLIPKEY = "File_Clipboard";
        private List<FileItem> GetClip()
        {
            var list = Session[CLIPKEY] as List<FileItem>;
            if (list == null) Session[CLIPKEY] = list = new List<FileItem>();

            return list;
        }

        /// <summary>复制文件到剪切板</summary>
        /// <param name="r"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Detail)]
        public ActionResult Copy(String r, String f)
        {
            var fi = GetItme(f);
            if (fi == null) throw new Exception("找不到文件或目录!");

            var list = GetClip();
            if (!list.Any(e => e.Raw == fi.Raw)) list.Add(fi);

            //return RedirectToAction("Index", new { r });
            return Index(r, null);
        }

        /// <summary>从剪切板移除</summary>
        /// <param name="r"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Detail)]
        public ActionResult CancelCopy(String r, String f)
        {
            var fi = GetItme(f);
            if (fi == null) throw new Exception("找不到文件或目录!");

            var list = GetClip();
            list.RemoveAll(e => e.Raw == fi.Raw);

            //return RedirectToAction("Index", new { r });
            return Index(r, null);
        }

        /// <summary>粘贴文件到当前目录</summary>
        /// <param name="r"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Insert)]
        public ActionResult Paste(String r)
        {
            var di = GetDirectory(r) ?? Root.AsDirectory();
            if (di == null) throw new Exception("找不到目录!");

            var list = GetClip();
            foreach (var item in list)
            {
                var dst = di.FullName.CombinePath(item.Name);
                WriteLog("复制", "{0} => {1}".F(item.Raw, dst));
                if (item.Directory)
                    item.Raw.AsDirectory().CopyTo(dst);
                else
                    System.IO.File.Copy(item.Raw, dst, true);
            }
            list.Clear();

            return Index(r, null);
        }

        /// <summary>移动文件到当前目录</summary>
        /// <param name="r"></param>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Insert)]
        public ActionResult Move(String r)
        {
            var di = GetDirectory(r) ?? Root.AsDirectory();
            if (di == null) throw new Exception("找不到目录!");

            var list = GetClip();
            foreach (var item in list)
            {
                var dst = di.FullName.CombinePath(item.Name);
                WriteLog("移动", "{0} => {1}".F(item.Raw, dst));
                if (item.Directory)
                    Directory.Move(item.Raw, dst);
                else
                    System.IO.File.Move(item.Raw, dst);
            }
            list.Clear();

            return Index(r, null);
        }

        /// <summary>清空剪切板</summary>
        /// <returns></returns>
        [EntityAuthorize(PermissionFlags.Detail)]
        public ActionResult ClearClipboard(String r)
        {
            var list = GetClip();
            list.Clear();

            return Index(r, null);
        }
        #endregion

        #region 日志
        private static void WriteLog(String action, String remark)
        {
            LogProvider.Provider.WriteLog(typeof(FileController), action, remark);
        }
        #endregion
    }
}