Asp.Net Core写个共享磁盘文件Web查看器

Posted 神牛003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Asp.Net Core写个共享磁盘文件Web查看器相关的知识,希望对你有一定的参考价值。

本篇和大家分享的是一个磁盘文件查看系统,严格来说是使用NetCore写的一个Web系统应用,由于NetCore跨平台特性,我生成了exe的运行包,只需要配置运行电脑ip+端口,即可在浏览器中通过IP+端口的方式访问目标调用上的所有目录,不错是所有目录(如果您有:C,D,E,F盘都可以访问),当然为了安全最好限制下;还有上传,备份功能,具体看下面的分享内容吧;git地址:https://github.com/shenniubuxing3/ShenNiu.LogTool

查看器功能说明与演示

本查看器主要是为了方便大家查看服务器上的日志,这里没有考虑其他安全性问题,比如特定人员登录才能查看,这个需要您们自己去增加;如果你服务器有对外开放了ip,那么运行这个软件的时候建议考虑配置成您们公司内网的ip,这里可以避免一些安全性问题;下面是主要功能:

. 通过可以定义文件配置常用磁盘访问地址

. 查看磁盘目录下的文件夹和文件

. 部分可访问行文件(如:txt,DLL,图片等)可以在浏览器中打开或下载(访问性格式由程序配置)

. 上传多个文件到指定磁盘

. 文件备份(如果上传的文件已经存在,会自动备份到bak文件夹中)

效果gif图片,有点花多多包涵:

效果还可以吧,不妨“推荐”下;

 

磁盘列表功能

首先,要明确的是在NetCore1.1中api已经和大部分能和framwork对应上了(据@善友一篇博客简单介绍说NetCore2.0的api已经能够和framwork持平了),因此这里我们能够直接使用DirectoryInfo,来查看磁盘路径的文件夹和文件,所以就有了查看列表Action的代码:

 1  /// <summary>
 2         /// 磁盘列表
 3         /// </summary>
 4         /// <param name="path">磁盘路径</param>
 5         /// <returns></returns>
 6         public IActionResult Index(string path)
 7         {
 8             Console.WriteLine($"IP:{HttpContext.Connection.RemoteIpAddress}正在查看磁盘:{path}");
 9             var list = new List<FileSystemInfo>();
10             MoSearch moSerach = new MoSearch { Txt1 = path };
11             ViewData["Search"] = moSerach;
12 
13             if (string.IsNullOrWhiteSpace(path)) { return View(list); }
14             if (path.StartsWith("c:", StringComparison.OrdinalIgnoreCase)) { this.MsgBox($"无权限访问:{path}"); return View(list); }
15             if (!System.IO.Directory.Exists(path)) { this.MsgBox($"磁盘路径:{path}不存在!"); return View(list); }
16             DirectoryInfo dic = new DirectoryInfo(path);
17             list = dic.GetFileSystemInfos().OrderByDescending(b => b.LastWriteTime).ToList();
18 
19             return View(list);
20         }

这里我默认限制了C盘,并且采用自带的文件对象FileSystemInfo来返回信息,仅仅只需要一段 dic.GetFileSystemInfos().OrderByDescending(b => b.LastWriteTime).ToList() 就能获取按照最新修改时间得到磁盘目录信息;对应的View布局如下:

  1 @using System.IO
  2 @using ShenNiu.LogTool.Extension;
  3 @using ShenNiu.LogTool.Controllers
  4 @model List<FileSystemInfo>
  5 @{
  6     ViewData["Title"] = "日志搜索";
  7 
  8     var moSearch = ViewData["Search"] as MoSearch;
  9 }
 10 <div>
 11     <h4>@ViewData["Title"]</h4>
 12     <hr />
 13     <form id="form01" method="post" enctype="multipart/form-data">
 14         <div class="form-group">
 15             <label for="txt1">磁盘路径</label>
 16             <input type="text" class="form-control" id="txt1" name="txt1" value="@moSearch.Txt1" style="max-width:100%" placeholder="会记录到后面的下拉框">
 17         </div>
 18         <div class="form-group">
 19             <label for="sel1">常用地址</label>
 20             <select name="sel1" id="sel1" class="form-control">
 21                 @*<option value="">==请选择==</option>
 22                     <optgroup label="日志">
 23                         <option value="D:\\D\\Joke">D:\\D\\Joke</option>
 24                     </optgroup>
 25                     <optgroup label="D盘">
 26                         <option value="D:\\">D盘</option>
 27                     </optgroup>*@
 28             </select>
 29 
 30         </div>
 31         <div class="form-group ">
 32             <input type="file" name="upFile" class="form-control" multiple placeholder="上传文件" />
 33         </div>
 34         <button type="button" id="btnSearch" class="btn btn-default">查 询</button>
 35         <button type="button" id="btnUp" class="btn btn-default ">上 传</button>
 36         <a href="javascript:window.history.go(-1);" class="btn btn-default">返 回</a>
 37         <span id="span01" style="color:red">
 38             @ViewData["msg"]
 39         </span>
 40     </form>
 41     <hr />
 42     <table class="table">
 43         <thead>
 44             <tr>
 45                 <th>文件名</th>
 46                 <th>磁盘路径</th>
 47                 <th>最后更新时间</th>
 48                 <th>创建时间</th>
 49                 <th>操作</th>
 50             </tr>
 51         </thead>
 52         <tbody>
 53             @foreach (var item in Model)
 54             {
 55             <tr>
 56                 <td>
 57                     @if (item.Attributes == FileAttributes.Archive)
 58                         {
 59                         <img src="/images/icon/@(item.Extension.GetExtensionIcon())" /><a href="/log/read?path=@item.FullName" target="_blank">@item.Name</a>
 60                         }
 61                         else if (item.Attributes == FileAttributes.Directory)
 62                         {
 63                         <img src="/images/icon/Directory1.jpg" /><a href="/log/index?path=@item.FullName">@item.Name</a>
 64                         }
 65                         else
 66                         {
 67                         <img src="/images/icon/@(item.Extension.GetExtensionIcon())" /><a href="/log/index?path=@item.FullName">@item.Name</a>
 68                         }
 69                     @item.Attributes
 70                 </td>
 71                 <td>@item.FullName</td>
 72                 <td>@item.LastWriteTime</td>
 73                 <td>@item.CreationTime</td>
 74                 <td>
 75                     @if (item.Attributes == FileAttributes.Archive)
 76                         {
 77                         <a href="/log/read?path=@item.FullName" target="_blank">查看</a>
 78                         }
 79                 </td>
 80             </tr>
 81             }
 82         </tbody>
 83     </table>
 84     <div style="color:red">@ViewData["msg"]</div>
 85 </div>
 86 <script type="text/javascript">
 87     $(function(){
 88 
 89     $("#btnUp").on("click", function () {
 90             var msg = $("#span01");
 91             var form = document.getElementById("form01");
 92             //console.log(form);
 93             var data = new FormData(form);
 94 
 95             $.ajax({
 96                 type: "POST",
 97                 url: "/log/AjaxFileUp",
 98                 data: data,
 99 
100                 contentType: false,
101                 processData: false,
102                 success: function (data) {
103                     if (data) {
104                         msg.html(data.msg);
105                     }
106                 },
107                 error: function () {
108                     msg.html("上传文件异常,请稍后重试!");
109                 }
110             });
111         });
112 
113         $("#btnSearch").on("click",function(){
114 
115          var sel1Val = $.trim($("select[name=\'sel1\'] option:selected").val());
116          var txt1Val = $.trim($("#txt1").val());
117 
118 
119          var pathVal = sel1Val.length<=0?txt1Val:sel1Val;
120          window.location.href="/log/index?path="+pathVal;
121         });
122 
123         $.getJSON("/log/GetSelData",function(data){
124             console.log(data);
125             if(data){
126 
127 
128 
129                 var sel1 = $("select[name=\'sel1\']");
130                 var gArr = [];
131                 gArr.push(\'<option value="">==请选择==</option>\');
132                 $.each(data,function(i,item){
133 
134                     gArr.push(\'<optgroup label="\'+item.gname+\'">\');
135 
136                     $.each(item.gval,function(i2,item2){
137 
138                          gArr.push(\'<option value="\'+item2.val+\'">\'+item2.name+\'</option>\');
139                     });
140 
141                     gArr.push(\'</optgroup>\');
142                 });
143 
144                 sel1.html(gArr.join(\'\'));
145             }
146         });
147     })
148 </script>

列表页面的常用地址来源有系统配置文件配置的,通过前端ajax调用接口获取配置的json内容,接口Action代码:

 1  public async Task<ContentResult> GetSelData()
 2         {
 3             var apiUrl = $"http://{Request.Host.Host}:{Request.Host.Port}/js/tooldata/logconf.json";
 4             var str = string.Empty;
 5             using (HttpClient client = new HttpClient())
 6             {
 7                 client.BaseAddress = new Uri(apiUrl);
 8                 str = await client.GetStringAsync(apiUrl);
 9             }
10             return Content(str);
11         }

配置文件格式和内容如:

 1 [
 2   {
 3     "gname": "日志",
 4     "gval": [
 5       {
 6         "name": "JokeLog",
 7         "val": "D:\\\\D\\\\Joke"
 8       }
 9     ]
10   },
11   {
12     "gname": "D盘",
13     "gval": [
14       {
15         "name": "D盘",
16         "val": "D:\\\\"
17       }
18     ]
19   }
20 ]

 

指定磁盘目录上传文件和自动备份

通常咋们有这样的情况,我们没有直接访问服务器的权限,想上传个东西很麻烦,每次只能通过运维(当然这是正规的流程),可是往往一些特殊情况不得不自己传递个东西发布,因此这里增加了上传功能,并且上传时候如果已存在相同文件,那么在覆盖之前会自动增加备份到tempbak中去;

 1 /// <summary>
 2         /// 本查看系统具有上传文件的功能
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpPost]
 6         public async Task<JsonResult> AjaxFileUp()
 7         {
 8             var data = new MoData { Msg = "上传失败" };
 9             try
10             {
11                 var upPath = Request.Form["txt1"];
12                 if (string.IsNullOrWhiteSpace(upPath)) { data.Msg = "请在【磁盘路径】输入框输入上传路径。"; return Json(data); }
13                 if (!System.IO.Directory.Exists(upPath)) { data.Msg = $"磁盘路径:{upPath}不存在!"; return Json(data); }
14                 upPath = upPath.ToString().TrimEnd(\'\\\\\');
15 
16                 var files = Request.Form.Files.Where(b => b.Name == "upFile");
17                 //非空限制
18                 if (files == null || files.Count() <= 0) { data.Msg = "请选择上传的文件。"; return Json(data); }
19 
20                 //格式限制
21                 //var allowType = new string[] { "image/jpeg", "image/png" };
22                 //if (files.Any(b => !allowType.Contains(b.ContentType)))
23                 //{
24                 //    data.Msg = $"只能上传{string.Join(",", allowType)}格式的文件。";
25                 //    return Json(data);
26                 //}
27 
28                 //大小限制
29                 var nMax = 20;
30                 if (files.Sum(b => b.Length) >= 1024 * 1024 * nMax)
31                 {
32                     data.Msg = $"上传文件的总大小只能在{nMax}M以下。"; return Json(data);
33                 }
34 
35                 //删除过去备份的文件
36                 var basePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "tempbak");
37                 DirectoryInfo dic = new DirectoryInfo(basePath);
38                 var nCount = dic.GetFiles().Count();
39                 var nMaxCount = 10;
40                 if (nCount > nMaxCount)  //大于nMaxCount个文件清空临时目录
41                 {
42                     foreach (var item in dic.GetFiles().OrderBy(b => b.LastWriteTime).Take(nCount - nMaxCount))
43                     {
44                         try
45                         {
46                             item.Delete();
47                         }
48                         catch (Exception ex) { }
49                     }
50                 }
51 
52                 //写入服务器磁盘
53                 var upLog = new StringBuilder(string.Empty);
54                 foreach (var file in files)
55                 {
56 
57                     var fileName = file.FileName;
58                     var path = Path.Combine(upPath, fileName);
59                     upLog.AppendFormat("文件:{0};", path);
60 
61                     //存在文件需要备份
62                     if (System.IO.File.Exists(path))
63                     {
64                         FileInfo info = new FileInfo(path);
65                         var tempPath = Path.Combine(basePath, info.Name); //备份目录
66                         var newInfo = info.CopyTo(tempPath, true);
67                         if (newInfo == null) { upLog.Append($"备份:失败,请稍后重试!"); }
68                         else { upLog.Append($"备份:成功!"); }
69                     }
70 
71                     using (var stream = System.IO.File.Create(path))
72                     {
73                         await file.CopyToAsync(stream);
74                     }
75                     upLog.Append($"上传:成功;<br/>");
76                 }
77                 data.Msg = upLog.ToString();
78                 data.Status = 2;
79             }
80             catch (Exception ex)
81             {
82                 data.Msg += ex.Message;
83             }
84             Console.WriteLine($"IP:{HttpContext.Connection.RemoteIpAddress}正在上传:{data.Msg}");
85             return Json(data);
86         }

关键点的逻辑代码已经有注释了这里就不多说了,主要满足咋们的业务:上传+备份;至于上传的js代码已经在上面的列表试图中了这里就不重复贴出来了;这里用到了几个自定义实体类:

 1 /// <summary>
 2     /// 接口统一类
 3     /// </summary>
 4     public class MoData
 5     {
 6         public string Msg { get; set; }
 7 
 8         public int Status { get; set; }
 9     }
10 
11     /// <summary>
12     /// 搜索类
13     /// </summary>
14     public class MoSearch
15     {
16         public string Txt1 { get; set; }
17 
18         public string Sel1 { get; set; }
19     }
20 
21     /// <summary>
22     /// 文件
23     /// </summary>
24     public class MoFile
25     {
ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

asp.net怎么配置IIS6

asp.net web.config的设置问题

ASP.NET Core 6框架揭秘实例演示[29]:搭建文件服务器

ASP.NET访问网络驱动器(映射磁盘)

asp.net core 2 从本地磁盘驱动器加载和显示图像