本篇和大家分享的是一个磁盘文件查看系统,严格来说是使用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的代码:

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

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

 @using System.IO
@using ShenNiu.LogTool.Extension;
@using ShenNiu.LogTool.Controllers
@model List<FileSystemInfo>
@{
ViewData["Title"] = "日志搜索"; var moSearch = ViewData["Search"] as MoSearch;
}
<div>
<h4>@ViewData["Title"]</h4>
<hr />
<form id="form01" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="txt1">磁盘路径</label>
<input type="text" class="form-control" id="txt1" name="txt1" value="@moSearch.Txt1" style="max-width:100%" placeholder="会记录到后面的下拉框">
</div>
<div class="form-group">
<label for="sel1">常用地址</label>
<select name="sel1" id="sel1" class="form-control">
@*<option value="">==请选择==</option>
<optgroup label="日志">
<option value="D:\D\Joke">D:\D\Joke</option>
</optgroup>
<optgroup label="D盘">
<option value="D:\">D盘</option>
</optgroup>*@
</select> </div>
<div class="form-group ">
<input type="file" name="upFile" class="form-control" multiple placeholder="上传文件" />
</div>
<button type="button" id="btnSearch" class="btn btn-default">查 询</button>
<button type="button" id="btnUp" class="btn btn-default ">上 传</button>
<a href="javascript:window.history.go(-1);" class="btn btn-default">返 回</a>
<span id="span01" style="color:red">
@ViewData["msg"]
</span>
</form>
<hr />
<table class="table">
<thead>
<tr>
<th>文件名</th>
<th>磁盘路径</th>
<th>最后更新时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@if (item.Attributes == FileAttributes.Archive)
{
<img src="/images/icon/@(item.Extension.GetExtensionIcon())" /><a href="/log/read?path=@item.FullName" target="_blank">@item.Name</a>
}
else if (item.Attributes == FileAttributes.Directory)
{
<img src="/images/icon/Directory1.jpg" /><a href="/log/index?path=@item.FullName">@item.Name</a>
}
else
{
<img src="/images/icon/@(item.Extension.GetExtensionIcon())" /><a href="/log/index?path=@item.FullName">@item.Name</a>
}
@item.Attributes
</td>
<td>@item.FullName</td>
<td>@item.LastWriteTime</td>
<td>@item.CreationTime</td>
<td>
@if (item.Attributes == FileAttributes.Archive)
{
<a href="/log/read?path=@item.FullName" target="_blank">查看</a>
}
</td>
</tr>
}
</tbody>
</table>
<div style="color:red">@ViewData["msg"]</div>
</div>
<script type="text/javascript">
$(function(){ $("#btnUp").on("click", function () {
var msg = $("#span01");
var form = document.getElementById("form01");
//console.log(form);
var data = new FormData(form); $.ajax({
type: "POST",
url: "/log/AjaxFileUp",
data: data, contentType: false,
processData: false,
success: function (data) {
if (data) {
msg.html(data.msg);
}
},
error: function () {
msg.html("上传文件异常,请稍后重试!");
}
});
}); $("#btnSearch").on("click",function(){ var sel1Val = $.trim($("select[name='sel1'] option:selected").val());
var txt1Val = $.trim($("#txt1").val()); var pathVal = sel1Val.length<=?txt1Val:sel1Val;
window.location.href="/log/index?path="+pathVal;
}); $.getJSON("/log/GetSelData",function(data){
console.log(data);
if(data){ var sel1 = $("select[name='sel1']");
var gArr = [];
gArr.push('<option value="">==请选择==</option>');
$.each(data,function(i,item){ gArr.push('<optgroup label="'+item.gname+'">'); $.each(item.gval,function(i2,item2){ gArr.push('<option value="'+item2.val+'">'+item2.name+'</option>');
}); gArr.push('</optgroup>');
}); sel1.html(gArr.join(''));
}
});
})
</script>

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

  public async Task<ContentResult> GetSelData()
{
var apiUrl = $"http://{Request.Host.Host}:{Request.Host.Port}/js/tooldata/logconf.json";
var str = string.Empty;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
str = await client.GetStringAsync(apiUrl);
}
return Content(str);
}

配置文件格式和内容如:

 [
{
"gname": "日志",
"gval": [
{
"name": "JokeLog",
"val": "D:\\D\\Joke"
}
]
},
{
"gname": "D盘",
"gval": [
{
"name": "D盘",
"val": "D:\\"
}
]
}
]

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

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

 /// <summary>
/// 本查看系统具有上传文件的功能
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<JsonResult> AjaxFileUp()
{
var data = new MoData { Msg = "上传失败" };
try
{
var upPath = Request.Form["txt1"];
if (string.IsNullOrWhiteSpace(upPath)) { data.Msg = "请在【磁盘路径】输入框输入上传路径。"; return Json(data); }
if (!System.IO.Directory.Exists(upPath)) { data.Msg = $"磁盘路径:{upPath}不存在!"; return Json(data); }
upPath = upPath.ToString().TrimEnd('\\'); var files = Request.Form.Files.Where(b => b.Name == "upFile");
//非空限制
if (files == null || files.Count() <= ) { data.Msg = "请选择上传的文件。"; return Json(data); } //格式限制
//var allowType = new string[] { "image/jpeg", "image/png" };
//if (files.Any(b => !allowType.Contains(b.ContentType)))
//{
// data.Msg = $"只能上传{string.Join(",", allowType)}格式的文件。";
// return Json(data);
//} //大小限制
var nMax = ;
if (files.Sum(b => b.Length) >= * * nMax)
{
data.Msg = $"上传文件的总大小只能在{nMax}M以下。"; return Json(data);
} //删除过去备份的文件
var basePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "tempbak");
DirectoryInfo dic = new DirectoryInfo(basePath);
var nCount = dic.GetFiles().Count();
var nMaxCount = ;
if (nCount > nMaxCount) //大于nMaxCount个文件清空临时目录
{
foreach (var item in dic.GetFiles().OrderBy(b => b.LastWriteTime).Take(nCount - nMaxCount))
{
try
{
item.Delete();
}
catch (Exception ex) { }
}
} //写入服务器磁盘
var upLog = new StringBuilder(string.Empty);
foreach (var file in files)
{ var fileName = file.FileName;
var path = Path.Combine(upPath, fileName);
upLog.AppendFormat("文件:{0};", path); //存在文件需要备份
if (System.IO.File.Exists(path))
{
FileInfo info = new FileInfo(path);
var tempPath = Path.Combine(basePath, info.Name); //备份目录
var newInfo = info.CopyTo(tempPath, true);
if (newInfo == null) { upLog.Append($"备份:失败,请稍后重试!"); }
else { upLog.Append($"备份:成功!"); }
} using (var stream = System.IO.File.Create(path))
{
await file.CopyToAsync(stream);
}
upLog.Append($"上传:成功;<br/>");
}
data.Msg = upLog.ToString();
data.Status = ;
}
catch (Exception ex)
{
data.Msg += ex.Message;
}
Console.WriteLine($"IP:{HttpContext.Connection.RemoteIpAddress}正在上传:{data.Msg}");
return Json(data);
}

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

 /// <summary>
/// 接口统一类
/// </summary>
public class MoData
{
public string Msg { get; set; } public int Status { get; set; }
} /// <summary>
/// 搜索类
/// </summary>
public class MoSearch
{
public string Txt1 { get; set; } public string Sel1 { get; set; }
} /// <summary>
/// 文件
/// </summary>
public class MoFile
{
public string Name { get; set; }
public string Path { get; set; }
public string Url { get; set; }
public string Content { get; set; }
public FileAttributes Attributes { get; set; }
}

直接查看内容

该系统可以直接查看如:txt,log等后缀的文件,因为这种类型的文件一般都有读,写同时操作的情况,所以这里我采用的方式是先拷贝当前访问的文件到temp临时目录中,然后在读取内容或下载文件;当满足超过10个文件的设置,那么自动删除修改时间最小的文件,避免拷贝文件一直增多导致磁盘空间的成本;下面是读取Action的内容:

 /// <summary>
/// 查看内容
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public async Task<IActionResult> Read(string path)
{
Console.WriteLine($"IP:{HttpContext.Connection.RemoteIpAddress}正在查看文件:{path}"); var moFile = new MoFile { Path = path };
if (string.IsNullOrWhiteSpace(path)) { this.MsgBox($"文件路径:{path}不存在。"); return View(moFile); }
if (!System.IO.File.Exists(path)) { this.MsgBox($"文件路径:{path}不存在!"); return View(moFile); } try
{
FileInfo info = new FileInfo(path);
//if (!ExtensionClass._AllowExtension.Any(b => b.ToUpper() == info.Extension.ToUpper()))
//{
// this.MsgBox($"无法访问{info.Extension}的文件"); return View(moFile);
// } var basePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "temp");
DirectoryInfo dic = new DirectoryInfo(basePath);
var nCount = dic.GetFiles().Count();
var nMaxCount = ;
if (nCount > nMaxCount) //大于nMaxCount个文件清空临时目录
{
foreach (var item in dic.GetFiles().OrderBy(b => b.LastWriteTime).Take(nCount - nMaxCount))
{
try
{
item.Delete();
}
catch (Exception ex) { }
}
} var tempPath = Path.Combine(basePath, info.Name);
var newInfo = info.CopyTo(tempPath, true);
if (newInfo == null) { this.MsgBox($"文件:{path}查看失败,请稍后重试!"); return View(moFile); } moFile.Name = newInfo.Name;
moFile.Url = $"/{moFile.Name}";
moFile.Attributes = newInfo.Attributes;
if (moFile.Attributes == FileAttributes.Archive && !ExtensionClass._FileExtension.Any(b => b == newInfo.Extension))
{
using (var stream = newInfo.OpenRead())
{
using (var reader = new StreamReader(stream))
{
moFile.Content = await reader.ReadToEndAsync();
}
}
}
}
catch (Exception ex)
{
this.MsgBox($"文件:{path}查看失败,请稍后重试!");
}
return View(moFile);
}

怎么使用ShenNiu.LogTool工具呢

我这里只提供了一个windows x64平台的运行exe包ShenNiu.LogTool(不用安装什么运行环境),只需要双击“ShenNiu.LogTool.exe”-》配置Ip+端口(默认IP:127.0.0.1,端口:12345):

-》浏览器中输入:http://127.0.0.1:12345/Log 即可访问查看系统,剩下的操作就如上gif截图了;

使用nssm工具把NetCore生成的exe转成windows服务

本篇到这里还要讲一个工具nssm(这里不提供下载地址,个位网搜吧),因为就windows平台而言netcore生成如果不用iis发布,那么大多数都是通过exe来运行的,但是我们不可能再服务器上开很多个黑屏cmd一样的窗体,那这样服务器每次关闭的话那就用不了服务了;因此我们使用nssm把这个netcore上传的exe转成windows服务中去,这样就算关机重启也能及时启动;

由于windows服务不会提示让咋们输入绑定的ip,端口,所以这里我们需要改改代码:

 public static void Main(string[] args)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Console.OutputEncoding = Encoding.GetEncoding("GB2312"); //Console.WriteLine("输入服务绑定的Ip:");
//var strHost = Console.ReadLine(); if (string.IsNullOrWhiteSpace(strHost)) { strHost = "127.0.0.1"; }
//Console.WriteLine("输入服务绑定的端口:");
//var strPort = Console.ReadLine(); if (string.IsNullOrWhiteSpace(strPort)) { strPort = "12345"; } //var hostAndPort = $"http://{strHost}:{strPort}";
var hostAndPort = "http://127.0.0.1:12345"; var host = new WebHostBuilder()
.UseKestrel()
.UseUrls(hostAndPort)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build(); host.Run();
}

然后利用nssm工具,首先通过cmd命令执行如下命令:

执行后会弹出一个框,然后如图操作:

再点击“install server”,不出意外的话会弹出一个 successful的提示;再来咋们看看windows服务中我们注册的服务:

这个时候该服务是未启动状态,所以我们可以直接通过操作界面启动下(当然也可以通过nssm命令启动),能正常启动没问题的话,我们就可以在浏览器中访问:http://127.0.0.1:12345/Log:

好了本章到此就结束了,怎么样干货还是可以吧,不妨点个"推荐",谢谢。再发下git地址:https://github.com/shenniubuxing3/ShenNiu.LogTool

Asp.Net Core写个共享磁盘文件Web查看器的更多相关文章

  1. 使用Http-Repl工具测试ASP.NET Core 2.2中的Web Api项目

    今天,Visual Studio中没有内置工具来测试WEB API.使用浏览器,只能测试http GET请求.您需要使用Postman,SoapUI,Fiddler或Swagger等第三方工具来执行W ...

  2. 给 asp.net core 写一个简单的健康检查

    给 asp.net core 写一个简单的健康检查 Intro 健康检查可以帮助我们知道应用的当前状态是不是处于良好状态,现在无论是 docker 还是 k8s 还是现在大多数的服务注册发现大多都提供 ...

  3. 给 asp.net core 写个中间件来记录接口耗时

    给 asp.net core 写个中间件来记录接口耗时 Intro 写接口的难免会遇到别人说接口比较慢,到底慢多少,一个接口服务器处理究竟花了多长时间,如果能有具体的数字来记录每个接口耗时多少,别人再 ...

  4. ASP.NET Core中的jQuery Unobtrusive Ajax帮助器

    最近在ASP.NET Core下写文章管理系统时,准备在分页显示文章内容时,使用Ajax.网上找了篇帖文,简单翻一下,仅供自己查阅. 原链接:https://dotnetthoughts.net/jq ...

  5. 【ASP.NET Core】体验一下 Mini Web API

    在上一篇水文中,老周给大伙伴们简单演示了通过 Socket 编程的方式控制 MPD (在树莓派上).按照计划,老周还想给大伙伴们演示一下使用 Web API 来封装对 MPD 控制.思路很 Easy, ...

  6. ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API

    原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio 作者:Mike Wasson 和 Rick Anderso ...

  7. 使用静态基类方案让 ASP.NET Core 实现遵循 HATEOAS Restful Web API

    Hypermedia As The Engine Of Application State (HATEOAS) HATEOAS(Hypermedia as the engine of applicat ...

  8. DataProtection设置问题引起不同ASP.NET Core站点无法共享用户验证Cookie

    这是这两天ASP.NET Core迁移中遇到的一个问题.2个ASP.NET Core站点(对应于2个不同的ASP.NET Core Web应用程序),2个站点都可以登录,但在其中任1个站点登录后,在当 ...

  9. 在ASP.NET Core MVC中构建简单 Web Api

    Getting Started 在 ASP.NET Core MVC 框架中,ASP.NET 团队为我们提供了一整套的用于构建一个 Web 中的各种部分所需的套件,那么有些时候我们只需要做一个简单的 ...

随机推荐

  1. Java --- JSP2新特性

    自从03年发布了jsp2.0之后,新增了一些额外的特性,这些特性使得动态网页设计变得更加容易.jsp2.0以后的版本统称jsp2.主要的新增特性有如下几个: 直接配置jsp属性 表达式语言(EL) 标 ...

  2. MongoDB数据库安装及配置环境终极教程(windows10系统)

    本文是笔者花时间踩坑踩生气了写出来的!转载请注明出处@http://www.cnblogs.com/tim100/!请尊重我的劳动成果!谢谢! 今天,给大家说说在windows10系统下MongoDB ...

  3. sublime text 3 打造舒适黑色主题

    效果: 这里我使用了两个主题插件组合成的 Spacegray Afterglow Ctrl+Shift+P -> Package Control:Install Packages 分别输入Spa ...

  4. 第二章 Struts 2的应用

    2.1 Struts 2的应用    2.1.1 使用步骤        1.创建web项目,添加jar包,创建helloWorld.jsp页面        2.创建HelloWorldAction ...

  5. JS事件处理程序

    JS事件处理程序:HTML事件处理程序.DOM0级事件处理程序.DOM2级事件处理程序.IE事件处理程序.跨浏览器的事件处理程序. HTML事件处理程序 <script type="t ...

  6. React的学习(下)

    摘要 众所周知,前端三大框架Angular.React.Vue,所以为了跟上时代的步伐,最近开始着手学习React,这时候就发现个大问题,框架一直在更新,提倡的编写语法也在更新,网上有许多教程都是一两 ...

  7. 函数, lambda表达式

    函数 函数:简单的理解,就是一次执行很多行代码 函数的返回值 函数的参数,和变量没区别 例: def hello(): print "hello world" hello() he ...

  8. 看我如何从一个APK到最终拿下域管理权限

    本文我将向大家介绍在企业网络中使用个人智能手机,会给我们企业网络造成怎样的潜在威胁?事实证明,想要欺骗一位企业内部的员工并让其安装恶意应用程序,其实并不困难.一旦成功,攻击者就可以突破企业内网的防护机 ...

  9. php中print_r、var_dump和var_export几个函数的用法区别

    php中print_r.var_dump和var_export几个函数的用法区别

  10. 在Angular项目下使用Umeditor

    Umeditor是百度旗下的开源富文本编辑器项目,目前用于百度贴吧,是ueditor的迷你版本. 公司的Angular后台管理项目需要上传一些新闻,用Umeditor十分适合.但是目前官方只提供Jsp ...