using Ips.Library.Basic; using Ips.Library.WebApi; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ips.Library.WebApi { /// /// 文件操作接口 /// 可通过浏览器访问http://{baseurl}/upload地址预览文件 /// public class FileController : BaseController { /// /// 上传文件(随机生成文件名) /// /// 表单文件集合 /// [HttpPost] public async Task>> UploadWithRandom(List files) { if (files.Count == 0) return Error>("请选择文件"); string uploadDir = "Upload"; string time = DateTime.Now.ToString("yyyyMMdd_HH"); string path = Path.Combine(AppContext.BaseDirectory, uploadDir, time);//子目录 Directory.CreateDirectory(path); var result = new List(); foreach (var file in files) { var filename = Path.GetFileName(file.FileName); if (filename.IsNull()) continue; var fileext = Path.GetExtension(filename).ToLower(); Directory.CreateDirectory(path); //重新命名文件 var pre = DateTime.Now.ToString("yyyyMMddHHmmssfff"); var seed = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0); var after = new Random(seed).Next(1000, 9999); var fileloadname = $"{pre}_{after}_{ProExt(fileext)}"; using (var stream = new FileStream(Path.Combine(path, fileloadname), FileMode.Create)) { await file.CopyToAsync(stream); } string fileUrl = $"{uploadDir}/{time}/{fileloadname}"; result.Add(fileUrl); } return Success(result); } /// /// 上传文件(保留文件名) /// /// 表单文件集合 /// 是否覆盖已经存在的本地文件 /// [HttpPost] public async Task>> Upload(List files, bool overwriteExisted = true) { if (files.Count == 0) return Error>("请选择文件"); string uploadDir = "Upload"; string time = DateTime.Now.ToString("yyyyMMdd_HH"); string path = Path.Combine(AppContext.BaseDirectory, uploadDir, time);//子目录 Directory.CreateDirectory(path); var result = new List(); foreach (var file in files) { var filename = Path.GetFileName(file.FileName); if (filename.IsNull()) continue; string localFile = Path.Combine(path, filename); if (overwriteExisted) { using (var stream = new FileStream(localFile, FileMode.Create)) { await file.CopyToAsync(stream); } } else { if (!System.IO.File.Exists(localFile)) { using (var stream = new FileStream(localFile, FileMode.Create)) { await file.CopyToAsync(stream); } } } string fileUrl = $"{uploadDir}/{time}/{filename}"; result.Add(fileUrl); } return Success(result); } /// /// 文件下载 /// /// 文件相对路径 /// [HttpGet] public IActionResult Download(string file) { if (string.IsNullOrWhiteSpace(file)) { return NotFound("必须指定要下载的文件"); } if (file.StartsWith("/")) file = file.Substring(1); string localFile = Path.Combine(AppContext.BaseDirectory, file); try { if (!System.IO.File.Exists(localFile)) { return NotFound($"文件[{localFile}]不存在"); } string fileName = Path.GetFileName(localFile); var fileStream = new FileStream(localFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, true); //异步读取文件 return File(fileStream, "application/octet-stream", fileName, true); //为true时,支持断点续传 } catch (Exception ex) { IpsLogger.Error($"文件[{localFile}]下载失败", ex); return NotFound($"文件[{localFile}]下载失败"); } } #region 校验文件类型 readonly string[] badext = { ".exe", ".msi", ".bat", ".com", ".sys", ".aspx", ".asax", ".ashx" }; private string ProExt(string ext) { if (ext.IsNull()) return ""; if (badext.Contains(ext)) throw new Exception("危险文件"); if (ext.First() == '.') return ext; return "." + ext; } #endregion } }