本文章向大家介绍.NET6 WebApi 大文件上传——分片上传,主要包括.NET6 WebApi 大文件上传——分片上传使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
最近遇到大文件上传问题,网上参考后写的小DEMO
WebApi代码
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using Polly;
using UploadFile.Models;
namespace UploadFile.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class UploadController : ControllerBase
{
[EnableCors("AllowSpecificOrigin")]
[HttpPost]
public async Task<IActionResult> RuleUploadFile([FromQuery] SliceFileInfo file)
{
try
{
string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Upload");
var files = Request.Form.Files;
var buffer = new byte[file.Size];
var fileName = file.Name;
path = path + "//" + fileName + "//";
if (!System.IO.Directory.Exists(path))
{
System.IO.Directory.CreateDirectory(path);
}
string filepath = path + "//" + file.Name + "^" + file.Number;
using (var stream = new FileStream(filepath, FileMode.Append))
{
await files[0].CopyToAsync(stream);
}
var filesList = Directory.GetFiles(Path.GetDirectoryName(path));
//当顺序号等于分片总数量 合并文件
if ((file.Number + 1) == file.Count || filesList.Length == file.Count)
{
await MergeFile(file);
}
return this.Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
/// <summary>
/// 合并文件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
private async Task MergeFile(SliceFileInfo file)
{
string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Upload");
var fileName = file.Name;
path = path + "//" + fileName + "//";
string baseFileName = path + fileName.Split("~")[0].ToString();
if (!System.IO.Directory.Exists(path))
{
System.IO.Directory.CreateDirectory(path);
}
var filesList = Directory.GetFiles(Path.GetDirectoryName(path));
if (filesList.Length != file.Count)
{
return;
}
List<FileSort> lstFile = new List<FileSort>();
foreach (var item in filesList)
{
lstFile.Add(new FileSort()
{
Name = item,
NumBer = Convert.ToInt32(item.Substring(item.IndexOf('^') + 1))
});
}
lstFile = lstFile.OrderBy(x => x.NumBer).ToList();
using (var fileStream = new FileStream(baseFileName, FileMode.Create))
{
//foreach (var fileSort in filesList)
//{
// using (FileStream fileChunk = new FileStream(fileSort, FileMode.Open))
// {
// await fileChunk.CopyToAsync(fileStream);
// }
//}
await Policy.Handle<IOException>()
.RetryForeverAsync()
.ExecuteAsync(async () =>
{
foreach (var fileSort in lstFile)
{
using (FileStream fileChunk = new FileStream(fileSort.Name, FileMode.Open))
{
await fileChunk.CopyToAsync(fileStream);
}
}
});
}
//删除分片文件
foreach (var dirfile in filesList)
{
System.IO.File.Delete(dirfile);
}
}
}
}
Program配置跨域
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin", cors =>
{
cors.AllowAnyOrigin();
cors.AllowAnyHeader();
//cors.AllowAnyMethod();
});
});
builder.Services.Configure<FormOptions>(options =>
{
options.KeyLengthLimit = int.MaxValue;
options.ValueLengthLimit = int.MaxValue;
options.MultipartBodyLengthLimit = int.MaxValue;
options.MultipartHeadersLengthLimit = int.MaxValue;
});
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = int.MaxValue;
options.Limits.MaxRequestBufferSize = int.MaxValue;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors("AllowSpecificOrigin");
app.UseAuthorization();
app.MapControllers();
app.Run();
前台VUE
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://unpkg.com/vue@3.2.31/dist/vue.global.js"></script>
<script src="https://unpkg.com/axios@0.26.1/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<input type="file" id="fileExport" @change="handleFileChange" ref="inputer">
<button @click="loadfile">开始上传</button>
<button @click="load">分片上传</button>
</div>
<script>
var obj = {
data() {
return {
Title: "上传文件",
file: {},
};
},
methods: {
handleFileChange(e) {
let inputDOM = this.$refs.inputer;
this.file = inputDOM.files[0];// 通过DOM取文件数据
},
loadfile() {
let size = Math.floor(this.file.size / 1024);//计算文件的大小
let formData = new FormData();//new一个formData事件
formData.append("files", this.file); //将file属性添加到formData里
debugger;
fetch("http://localhost:5128/Upload/RuleUploadFile", {
method: 'post',
body: formData,
headers: {
/*"Content-Type": "multipart/form-data;",*/
}
}).then(r => r.json()).then(r => {
console.log(r);
}).catch(e => {
console.log(e);
})
},
S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
},
guid() {
return (this.S4() + this.S4() + "-" + this.S4() + "-" + this.S4() + "-" + this.S4() + "-" + this.S4() + this.S4() + this.S4());
},
load() {
let size = this.file.size;//文件大小
let maxZrea = 8; //设置每个分区大小 MB
let bufferSize = maxZrea * (1024 * 1024);
let fileStart = 0;
let fileEnd = bufferSize;
let arrFile = [];
while (fileStart < size) {
var fileInfo = {
File: this.file.slice(fileStart, fileEnd),
Start: fileStart,
End: fileEnd
}
arrFile.push(fileInfo);
fileStart = fileEnd;
fileEnd = fileStart + bufferSize;
}
let count = arrFile.length;
let filename = this.file.name + "~" + this.guid();
for (var i = 0; i < count; i++) {
let formData = new FormData();//new一个formData事件
formData.append("file", arrFile[i].File); //将file属性添加到formData里
var url = "http://localhost:5128/Upload/RuleUploadFile?Name=" + filename + "&Number=" + i + "&BufferSize=" + bufferSize + "&Count=" + count + "&Start=" + arrFile[i].Start + "&End=" + arrFile[i].End + "&Size=" + size;
/*var url = "http://192.168.0.166:8080/Upload/RuleUploadFile?Name=" + filename + "&Number=" + i + "&BufferSize=" + bufferSize + "&Count=" + count + "&Start=" + arrFile[i].Start + "&End=" + arrFile[i].End + "&Size=" + size;*/
//fetch(url, {
// method: 'post',
// body: formData,
// headers: {
// /*"Content-Type": "multipart/form-data;",*/
// }
//}).then(r => r.json()).then(r => {
// console.log(r);
//}).catch(e => {
// console.log(e);
//})
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data;",
}
}).then(r => {
console.log(r);
}).catch(e => {
console.log(e);
});
}
}
}
};
var vm = Vue.createApp(obj).mount("#app");
</script>
</body>
</html>
实测1G文件本地开发环境上传速度在20秒左右,网络环境没有测试过
原文地址:https://www.cnblogs.com/lyzi/p/16008776.html
Copyright © 广州京杭网络科技有限公司 2005-2024 版权所有 粤ICP备16019765号
广州京杭网络科技有限公司 版权所有