이 장에서는 .NetCore의 MVC 프레임워크를 사용하여 파일을 업로드하는 예를 공유합니다. 주요 내용은 업로드를 위한 양식 제출, Ajax 업로드, Ajax 제출 + 업로드 진행 효과, 작업 병렬 처리 + Ajax 제출 + 업로드 진행, 관심 있는 친구들은 편집자를 따라가면서 함께 배울 수 있습니다
이 장에서는 .NetCore의 MVC 프레임워크를 사용하여 파일을 업로드하는 예를 공유합니다. 주요 내용은 양식 제출 및 업로드, ajax입니다. 업로드, ajax 제출 + 업로드 진행 효과, 작업 병렬 처리 + ajax 제출 + 업로드 진행. 가능하다면 기사 내용을 읽고 나면 좋은 결과를 얻을 수 있을 것입니다. 어제 컴퓨터 전원이 나가서 거의 다 쓰게 됐는데 내용이 저장이 안 돼서 오늘 아침 일찍 회사에 와서 처음부터 다시 시작했는데 정전이 정말 골치아팠지만 커뮤니티를 위해서였습니다. 환경 공유, 그만한 가치가 있었습니다. 더 이상 고민하지 말고 오늘의 주요 부분으로 들어가겠습니다.
양식으로 사진 세트 업로드
먼저 HTML 코드를 살펴보겠습니다. 다음은 파일을 업로드하는 데 필요한 사항에 대한 간략한 설명입니다. 여러 파일을 업로드하려면 enctype="multipart/form-data" 속성과 게시 방법을 설정하세요. , 파일 유형='파일' 요소를 속성 multiple='다중'으로 설정해야 합니다. 따라서 다음 콘텐츠가 포함됩니다.
<form class="form-horizontal" action="/Home/FileUp" method="post" enctype="multipart/form-data"> <input type="file" name="MyPhoto" class="form-control" multiple /> <br /> <button class="btn btn-default">form上传</button> <br /> <span style="color:red">@ViewData["MsgBox"]</span> </form>
양식 제출로 인해 이 테스트 케이스는 기본 type=submit 버튼 요소만 사용하여 양식을 제출하고 백그라운드 작업의 해당 코드는 다음과 같습니다.
/// <summary> /// form提交上传 /// </summary> /// <param name="user"></param> /// <returns></returns> [HttpPost] public async Task<IActionResult> FileUp(MoUser user) { if (user.MyPhoto == null || user.MyPhoto.Count <= 0) { MsgBox("请上传图片。"); return View(); } //var file = Request.Form.Files; foreach (var file in user.MyPhoto) { var fileName = file.FileName; var contentType = file.ContentType; var len = file.Length; var fileType = new string[] { "image/jpeg", "image/png" }; if (!fileType.Any(b => b.Contains(contentType))) { MsgBox($"只能上传{string.Join(",", fileType)}格式的图片。"); return View(); } if (len > 1024 * 1024 * 4) { MsgBox("上传图片大小只能在4M以下。"); return View(); } var path = Path.Combine(@"D:\F\学习\vs2017\netcore\netcore01\WebApp01\wwwroot\myfile", fileName); using (var stream = System.IO.File.Create(path)) { await file.CopyToAsync(stream); } } MsgBox($"上传成功"); return View(); }
프론트 엔드의 작업 백엔드에서는 이 양식 제출 방법이 매우 간단하다고 말씀드리고 싶습니다. 여기서 주목해야 할 점은 업로드된 파일 정보에 따라 여기에서 MoUser 클래스가 사용자 정의되고 는 html 형식의 public Listbd57100a971f76ffcb06f3d1bfb26aea MyPhoto { get; set; }
속성 이름 type='file'的name
파일과 일치하는 데 사용됩니다. name="MyPhoto"
public class MoUser { public int UserId { get; set; } = 1; public string UserName { get; set; } = "神牛步行3"; public List<IFormFile> MyPhoto { get; set; } }업로드된 파일 정보를 MyPhoto 속성에 저장할 수 있습니다.
ajax는 일련의 사진을 업로드합니다
여기서 HTML의 일부 항목을 수정해야 합니다. 위의 예에서는 양식 제출을 사용하는 대신 Ajax 제출을 트리거하는 일반 버튼 버튼을 지정합니다.<form class="form-horizontal" id="form01" method="post" enctype="multipart/form-data"> <input type="file" name="MyPhoto01" class="form-control" multiple /> <br /> <button type="button" id="btnAjax" class="btn btn-default">ajax上传</button> <br /> <span style="color:red" id="span01"></span> </form>특정 js 구현 코드를 살펴보겠습니다. 여기에서는 jquery의 ajax 제출 방법을 사용하고 html5의 새로운 FormData를 사용하여 양식 데이터를 저장합니다.
$("#btnAjax").on("click", function () { var msg = $("#span01"); var form = document.getElementById("form01"); //console.log(form); var data = new FormData(form); $.ajax({ type: "POST", url: "/home/AjaxFileUp", data: data, contentType: false, processData: false, success: function (data) { if (data) { msg.html(data.msg); } }, error: function () { msg.html("上传文件异常,请稍后重试!"); } }); });백그라운드 Action 메서드는 예제 1과 크게 다르지 않습니다. 여기서 중요한 점은 여기서는 Request.Form.Files 메서드를 직접 사용하여 업로드된 모든 파일을 가져오고 더 이상 엔터티 모델 메서드를 사용하지 않는다는 것입니다. , 테스트 사례를 더욱 다양하게 만들어 보겠습니다.
/// <summary> /// ajax无上传进度效果上传 /// </summary> /// <returns></returns> [HttpPost] public async Task<JsonResult> AjaxFileUp() { var data = new MoData { Msg = "上传失败" }; try { var files = Request.Form.Files.Where(b => b.Name == "MyPhoto01"); //非空限制 if (files == null || files.Count() <= 0) { 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); } //大小限制 if (files.Sum(b => b.Length) >= 1024 * 1024 * 4) { data.Msg = "上传文件的总大小只能在4M以下。"; return Json(data); } //写入服务器磁盘 foreach (var file in files) { var fileName = file.FileName; var path = Path.Combine(@"D:\F\学习\vs2017\netcore\netcore01\WebApp01\wwwroot\myfile", fileName); using (var stream = System.IO.File.Create(path)) { await file.CopyToAsync(stream); } } data.Msg = "上传成功"; data.Status = 2; } catch (Exception ex) { data.Msg = ex.Message; } return Json(data); }인내심을 갖고 이 글을 읽으신다면 개인적으로 다음 내용이 귀하의 개발에 큰 도움이 될 것이라고 생각합니다. 기대에 부응하세요.
ajax 제출 + 업로드 진행 + 이미지 업로드 세트
마찬가지로 해당 HTML 코드를 살펴보겠습니다. 먼저, 이름이 변경된 점을 제외하면 예제 2와 거의 동일합니다.<form class="form-horizontal" id="form02" method="post" enctype="multipart/form-data"> <input type="file" name="MyPhoto02" class="form-control" multiple /> <br /> <button type="button" id="btnAjax02" class="btn btn-default">ajax上传进度效果上传</button> <br /> <span style="color:red" id="span02"></span> </form>진행 효과를 추가하려면 js를 사용해야 합니다. 타이머는 업로드된 파일의 업로드 진행 상황을 정기적으로 가져오므로 여기서는 js의 setInterval 메소드를 사용하여 진행 데이터 인터페이스를 정기적으로 요청합니다. 그렇지 않으면 계속 요청하게 됩니다. 인터페이스:
$("#btnAjax02").on("click", function () { var interBar; var msg = $("#span02"); msg.html("上传中,请稍后..."); var form = document.getElementById("form02"); //console.log(form); var data = new FormData(form); $.ajax({ type: "POST", url: "/home/AjaxFileUp02", data: data, contentType: false, processData: false, success: function (data) { if (data) { msg.html(data.msg); //清除进度查询 if (interBar) { clearInterval(interBar); } } }, error: function () { msg.html("上传文件异常,请稍后重试!"); if (interBar) { clearInterval(interBar); } } }); //获取进度 interBar = setInterval(function () { $.post("/home/ProgresBar02", function (data) { if (data) { var isClearVal = true; var strArr = []; $.each(data, function (i, item) { strArr.push('文件:' + item.fileName + ",当前上传:" + item.percentBar + '<br/>'); if (item.status != 2) { isClearVal = false; } }); msg.html(strArr.join('')); if (isClearVal) { if (interBar) { clearInterval(interBar); } } } }); }, 200); });위에서 별도의 진행 데이터 인터페이스를 언급했으므로 업로드 작업 외에 진행 작업도 필요하며, 다음에서 얻은 업로드 파일 데이터 정보도 필요합니다. 진행 작업은 업로드 작업과 일치해야 하므로 캐시 및 기타 저장소를 사용해야 합니다. 데이터 메서드, 여기서는 MemoryCache 메서드를 사용합니다. netcore의 경우 시작 파일에 구성 요소 서비스(예: Startup)만 추가하면 됩니다. .cs):
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); //添加cache支持 services.AddDistributedMemoryCache(); }그런 다음 생성자를 통해 해당 인터페이스 Controller에 삽입합니다.
readonly IMemoryCache _cache; public HomeController(IOptions<MoOptions> options, ILogger<HomeController> logger, IMemoryCache cache) { this._options = options.Value; _logger = logger; _cache = cache; }여기서 캐시를 사용하여 업로드 진행 정보를 저장할 수 있으므로 업로드 처리 작업을 살펴보겠습니다.
private string cacheKey = "UserId_UpFile"; private string cacheKey03 = "UserId_UpFile03"; /// <summary> /// ajax上传进度效果上传 /// </summary> /// <returns></returns> [HttpPost] public async Task<JsonResult> AjaxFileUp02() { var data = new MoData { Msg = "上传失败" }; try { var files = Request.Form.Files.Where(b => b.Name == "MyPhoto02"); //非空限制 if (files == null || files.Count() <= 0) { 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); } //大小限制 if (files.Sum(b => b.Length) >= 1024 * 1024 * 4) { data.Msg = "上传文件的总大小只能在4M以下。"; return Json(data); } //初始化上传多个文件的Bar,存储到缓存中,方便获取上传进度 var listBar = new List<MoBar>(); files.ToList().ForEach(b => { listBar.Add(new MoBar { FileName = b.FileName, Status = 1, CurrBar = 0, TotalBar = b.Length }); }); _cache.Set<List<MoBar>>(cacheKey, listBar); //写入服务器磁盘 foreach (var file in files) { //总大小 var totalSize = file.Length; //初始化每次读取大小 var readSize = 1024L; var bt = new byte[totalSize > readSize ? readSize : totalSize]; //当前已经读取的大小 var currentSize = 0L; var fileName = file.FileName; var path = Path.Combine(@"D:\F\学习\vs2017\netcore\netcore01\WebApp01\wwwroot\myfile", fileName); using (var stream = System.IO.File.Create(path)) { //await file.CopyToAsync(stream); //进度条处理流程 using (var inputStream = file.OpenReadStream()) { //读取上传文件流 while (await inputStream.ReadAsync(bt, 0, bt.Length) > 0) { //当前读取的长度 currentSize += bt.Length; //写入上传流到服务器文件中 await stream.WriteAsync(bt, 0, bt.Length); //获取每次读取的大小 readSize = currentSize + readSize <= totalSize ? readSize : totalSize - currentSize; //重新设置 bt = new byte[readSize]; //设置当前上传的文件进度,并重新缓存到进度缓存中 var bars = _cache.Get<List<MoBar>>(cacheKey); var currBar = bars.Where(b => b.FileName == fileName).SingleOrDefault(); currBar.CurrBar = currentSize; currBar.Status = currentSize >= totalSize ? 2 : 1; _cache.Set<List<MoBar>>(cacheKey, bars); System.Threading.Thread.Sleep(1000 * 1); } } } } data.Msg = "上传完成"; data.Status = 2; } catch (Exception ex) { data.Msg = ex.Message; } return Json(data); }실제로 논리적으로 말하면 코드가 갑자기 더 많아집니다. 진행 상황을 저장하기 위해 캐시가 추가되고, 업로드된 파일 스트림을 하나씩 읽는 논리가 추가됩니다. 코드를 주의 깊게 보면 참고 사항과 설명이 있으며 다음과 같은 진행 정보가 있습니다.
[HttpPost] public JsonResult ProgresBar02() { var bars = new List<MoBar>(); try { bars = _cache.Get<List<MoBar>>(cacheKey); } catch (Exception ex) { } return Json(bars); }진행률 인터페이스는 캐시 정보만 가져오면 충분합니다. 참고: 이는 특정 사용 시나리오의 경우 다른 논리 코드를 추가하세요. 다음은 효과 스크린샷입니다.
작업 병렬 처리 + Ajax 제출 + 업로드 진행 + 이미지 업로드 세트
这一小节,将会使用Task来处理上传的文件,通过上一小节截图能够看出,如果你上传多个文件,那么都是按照次序一个一个读取文件流来生成上传文件到服务器,这里改良一下利用Task的特点,就能实现同时读取不同文件流了,先来看下html代码和js代码:
<form class="form-horizontal" id="form03" method="post" enctype="multipart/form-data"> <input type="file" name="MyPhoto03" class="form-control" multiple /> <br /> <button type="button" id="btnAjax03" class="btn btn-default">task任务处理ajax上传进度效果上传</button> <br /> <span style="color:red" id="span03"></span> </form>
由于和示例3的js代码无差别这里我直接贴出代码:
$("#btnAjax03").on("click", function () { var interBar; var msg = $("#span03"); msg.html("上传中,请稍后..."); var form = document.getElementById("form03"); //console.log(form); var data = new FormData(form); $.ajax({ type: "POST", url: "/home/AjaxFileUp03", data: data, contentType: false, processData: false, success: function (data) { if (data) { msg.html(data.msg); //清除进度查询 if (interBar) { clearInterval(interBar); } } }, error: function () { msg.html("上传文件异常,请稍后重试!"); if (interBar) { clearInterval(interBar); } } }); //获取进度 interBar = setInterval(function () { $.post("/home/ProgresBar03", function (data) { if (data) { var isClearVal = true; var strArr = []; $.each(data, function (i, item) { strArr.push('文件:' + item.fileName + ",当前上传:" + item.percentBar + '<br/>'); if (item.status != 2) { isClearVal = false; } }); msg.html(strArr.join('')); if (isClearVal) { if (interBar) { clearInterval(interBar); } } } }); }, 200); });
关键点在后台,通过task数组来存储每个上传文件的处理任务 Task[] tasks = new Task[len]; ,然后使用 Task.WaitAll(tasks); 等待所有上传任务的完成,这里特别注意了这里必须等待,不然会丢失上传文件流(多次测试结果):
/// <summary> /// ajax上传进度效果上传 /// </summary> /// <returns></returns> [HttpPost] public JsonResult AjaxFileUp03() { var data = new MoData { Msg = "上传失败" }; try { var files = Request.Form.Files.Where(b => b.Name == "MyPhoto03"); //非空限制 if (files == null || files.Count() <= 0) { 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); } //大小限制 if (files.Sum(b => b.Length) >= 1024 * 1024 * 4) { data.Msg = "上传文件的总大小只能在4M以下。"; return Json(data); } //初始化上传多个文件的Bar,存储到缓存中,方便获取上传进度 var listBar = new List<MoBar>(); files.ToList().ForEach(b => { listBar.Add(new MoBar { FileName = b.FileName, Status = 1, CurrBar = 0, TotalBar = b.Length }); }); _cache.Set<List<MoBar>>(cacheKey03, listBar); var len = files.Count(); Task[] tasks = new Task[len]; //写入服务器磁盘 for (int i = 0; i < len; i++) { var file = files.Skip(i).Take(1).SingleOrDefault(); tasks[i] = Task.Factory.StartNew((p) => { var item = p as IFormFile; //总大小 var totalSize = item.Length; //初始化每次读取大小 var readSize = 1024L; var bt = new byte[totalSize > readSize ? readSize : totalSize]; //当前已经读取的大小 var currentSize = 0L; var fileName = item.FileName; var path = Path.Combine(@"D:\F\学习\vs2017\netcore\netcore01\WebApp01\wwwroot\myfile", fileName); using (var stream = System.IO.File.Create(path)) { //进度条处理流程 using (var inputStream = item.OpenReadStream()) { //读取上传文件流 while (inputStream.Read(bt, 0, bt.Length) > 0) { //当前读取的长度 currentSize += bt.Length; //写入上传流到服务器文件中 stream.Write(bt, 0, bt.Length); //获取每次读取的大小 readSize = currentSize + readSize <= totalSize ? readSize : totalSize - currentSize; //重新设置 bt = new byte[readSize]; //设置当前上传的文件进度,并重新缓存到进度缓存中 var bars = _cache.Get<List<MoBar>>(cacheKey03); var currBar = bars.Where(b => b.FileName == fileName).SingleOrDefault(); currBar.CurrBar = currentSize; currBar.Status = currentSize >= totalSize ? 2 : 1; _cache.Set<List<MoBar>>(cacheKey03, bars); System.Threading.Thread.Sleep(1000 * 1); } } } }, file); } //任务等待 ,这里必须等待,不然会丢失上传文件流 Task.WaitAll(tasks); data.Msg = "上传完成"; data.Status = 2; } catch (Exception ex) { data.Msg = ex.Message; } return Json(data); }
至于获取上传进度的Action也仅仅只是读取缓存数据而已:
[HttpPost] public JsonResult ProgresBar03() { var bars = new List<MoBar>(); try { bars = _cache.Get<List<MoBar>>(cacheKey03); } catch (Exception ex) { } return Json(bars); }
这里再给出上传进度的实体类:
public class MoData { /// <summary> /// 0:失败 1:上传中 2:成功 /// </summary> public int Status { get; set; } public string Msg { get; set; } } public class MoBar : MoData { /// <summary> /// 文件名字 /// </summary> public string FileName { get; set; } /// <summary> /// 当前上传大小 /// </summary> public long CurrBar { get; set; } /// <summary> /// 总大小 /// </summary> public long TotalBar { get; set; } /// <summary> /// 进度百分比 /// </summary> public string PercentBar { get { return $"{(this.CurrBar * 100 / this.TotalBar)}%"; } } }
到此task任务处理上传文件的方式就完成了,咋们来看图看效果吧:
能够通过示例3和4的效果图对比出,没使用Task和使用的效果区别,这样效果您值得拥有,耐心读完本文内容的朋友,没让你失望吧,如果可以不妨点个"赞"或扫个码支持下作者,谢谢;内容最后附上具体测试用例代码:.NetCore上传多文件的几种示例
위 내용은 .NetCore를 사용하여 여러 파일을 업로드하는 예에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!