好久没有更新文章了,最近一直在出差。这次甲方希望系统可以下载日志文件以查看设备的启停运行情况,我就在页面中添加了一个按钮和一个下拉框来实现下载文件(毕竟新需求没给钱,怎么简单怎么做吧)
首先需要将日志文件(日志使用NLog进行记录,存放在了项目下的logs文件夹下)查询出来放入下拉框中,下拉框我使用的是 aspx控件dropdownlist,在页面加载时进行一次文件名查询和下拉框元素初始化,部分代码如下:
xxPage.aspx:
<asp:DropDownList id="fileName" runat="server" style="height:25px;width:140px;" >
</asp:DropDownList>
xxPage.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
//查询所有日志文件名称
var FilePath = System.Web.Hosting.HostingEnvironment.MapPath(@"~/logs/");
List<string> fileNames = getAllFiles(FilePath);
this.fileName.DataSource = fileNames;
this.fileName.DataBind();
}
/// <summary>
/// 获取所有文件
/// </summary>
/// <returns></returns>
private List<string> getAllFiles(string dir)
{
List<string> FilesList = new List<string>();
DirectoryInfo fileDire = new DirectoryInfo(dir);
if (!fileDire.Exists)
{
throw new System.IO.FileNotFoundException("目录:" + fileDire.FullName + "没有找到!");
}
this.getAllDirFiles(fileDire, FilesList);
this.getAllDirsFiles(fileDire.GetDirectories(), FilesList);
return FilesList;
}
/// <summary>
/// 获取一个文件夹下的所有文件夹里的文件
/// </summary>
/// <param name="dirs"></param>
/// <param name="filesList"></param>
private void getAllDirsFiles(DirectoryInfo[] dirs, List<string> filesList)
{
foreach (DirectoryInfo dir in dirs)
{
foreach (FileInfo file in dir.GetFiles("*.*"))
{
filesList.Add(file.Name);
}
this.getAllDirsFiles(dir.GetDirectories(), filesList);
}
}
/// <summary>
/// 获取一个文件夹下的文件
/// </summary>
/// <param name="strDirName">目录名称</param>
/// <param name="filesList">文件列表HastTable</param>
private void getAllDirFiles(DirectoryInfo dir, List<string> filesList)
{
foreach (FileInfo file in dir.GetFiles("*.*"))
{
//filesList.Add(file.LastWriteTime);
filesList.Add(file.Name);
}
}
接下来开始做下载部分,这里直接使用ajax来调用后台服务,获取指定文件的文件流,转为json数据传回给ajax,然后进行页面下载。部分代码如下:
xxPage.aspx:
<div id="controlLog"style="float:left; margin-top:10px;">
<a href="#" id="controlLog1" class="easyui-linkbutton" onclick="javascript:return onLogDownload()" style="height:35px;width:140px;text-align:center;line-height:35px">日志下载</a>
</div>
在这里没有使用form的submit提交,而是使用这个linkbutton纯粹是因为要与页面中其他按钮格式保持一致,使用什么方式提交其实都行。
xxPage.js:
function onLogDownload() { //2021-06-04
var fileName= $('select#fileName').find('option:selected').val();
var url = '../../WebPage/xxPage.ashx?method=logFileDownload&&logDate=' + fileName;
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true); // 也可以使用POST方式,根据接口
xhr.setRequestHeader("Content-Type", "application/json;charset=utf-8");
xhr.responseType = "blob"; // 返回类型blob
// 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
xhr.onload = function () {
// 请求完成
if (this.status === 200) {
// 返回200
var blob = this.response;
var reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a
reader.onload = function (e) {
// 转换完成,创建一个a标签用于下载
var a = document.createElement('a');
a.download = fileName;
a.href = e.target.result;
$("body").append(a); // 修复firefox中无法触发click
a.click();
$(a).remove();
}
}
};
// 发送ajax请求
xhr.send()
}
xxPage.ashx.cs:
#region 下载日志文件
public void logFileDownload(HttpContext context)
{
string json = string.Empty;
//获取前台参数
var logDate = Convert.ToString(context.Request.Params["logDate"]);
string URLAddress = System.Web.Hosting.HostingEnvironment.MapPath(@"~/logs/" + logDate);
try
{
using (FileStream fs = new FileStream(URLAddress, FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("gb2312")))
{
json = sr.ReadToEnd().ToString();
}
}
context.Response.Write(json);
//停止Response后续写入动作,保证Response内只有我们写入内容
context.Response.End();
}
catch (Exception ex)
{
throw;
}
}
#endregion
到这里需求就完成了,关于文件流转成json中文乱码的问题,解决很简单,就是在StreamReader创建时指定编码格式就好,使用Encoding.GetEncoding(“utf-8”)出现乱码的时候,一般改为Encoding.GetEncoding(“gb2312”)即可解决。
另外再写点多余的,也有一种需求是下载远程服务器文件到本机,这和上面的需求是不一样的:
- 这个需求是项目部署在本机,获取远程服务器文件到本机,可以使用WebClient来实现这个功能;
- 而上面的是项目部署在服务器,获取服务器文件到本机,需要使用ajax来实现下载。
关于WebClient获取远程地址文件的文章有很多,使用也很简单,如果有兴趣可自行查询。