FormData是HTML5新增的一个对象,通过FormData对象可以组装一组用 XMLHttpRequest发送请求的键/值对。它可以更灵活方便的发送表单数据,因为可以独立于表单使用。如果你把表单的编码类型设置为multipart/form-data ,则通过FormData传输的数据格式和表单通过submit() 方法传输的数据格式相同。具体用法参考 FormData对象的使用

  实现逻辑:客户端首先请求接口,获取一个唯一的UploadID,然后每次按照固定大小读取文件块,同时计算需要上传的总块数total,将UploadID、total、当前上传文件块的下标index、文件名称以及文件块上传到服务端,服务端根据以上参数把文件块保存到临时目录,同时判断文件块是否已经全部上传完,如果已全部上传,则需要进行合并操作,最后会返回合并后的文件信息。我的例子中,把获取UploadID的步骤跟上传放在了一起,上传接口中会判断如果UploadID为空并且index为1,则会生成一个UploadID并返回,后续每次上传都需要带上UploadID参数。

  一下前端代码

  前端代码

 @{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<meta name="viewport" content="width=device-width" />
<title>断点上传</title>
<script src="@Url.Content("~/Scripts/jquery-3.1.1.min.js")"></script>
</head>
<body>
<input id="myFile" type="file">
<button onclick="Start()">上传</button>
<button onclick="Pause()">暂停</button>
<button onclick="Continue()">继续</button>
<label>当前进度:<span id="progress"></span></label>
<script>
var uploadId = '';
var index = 1;
var pause = false; //暂停 function Start() {
index = 1;
uploadId = '';
Upload();
} function Upload() {
var files = document.getElementById('myFile').files;
if (files.length < 1) {
alert('请选择文件~');
return;
}
var file = files[0];
var totalSize = file.size;//文件大小
var blockSize = 1024 * 1024 * 2;//块大小
var blockCount = Math.ceil(totalSize / blockSize);//总块数 //创建FormData对象
var formData = new FormData();
formData.append('fileName', file.name);//文件名
formData.append('total', blockCount);//总块数
formData.append('index', index);//当前上传的块下标
formData.append('uploadId', uploadId);//上传编号
formData.append('data', null); UploadPost(file, formData, totalSize, blockCount, blockSize);
} function UploadPost(file, formData, totalSize, blockCount, blockSize) {
if (pause) {
return; //暂停
}
try {
var start = index * blockSize;
var end = Math.min(totalSize, start + blockSize);
var block = file.slice(start, end);
formData.set('data', block);
formData.set('index', index);
formData.set('uploadId', uploadId); $.ajax({
url: '',
type: 'post',
data: formData,
processData: false,
contentType: false,
success: function (res) {
block = null;
if (res.Code === 1) {
if (index === 1)
uploadId = res.UploadID; $('#progress').text((index / blockCount * 100).toFixed(2) + '%');
if (index < blockCount) {
index++;
UploadPost(file, formData, totalSize, blockCount, blockSize);
}
}
}
});
} catch (e) {
alert(e);
}
}
///暂停
function Pause() {
pause = true;
}
//继续
function Continue() {
pause = false;
Upload();
}
</script>
</body>
</html>

前端代码

  服务端代码

 using System;
using System.IO;
using System.Linq;
using System.Web; namespace UploadTest
{
public class UploadHelper
{ private UploadHelper()
{ } public UploadHelper(string fileRootPath)
{
if (string.IsNullOrWhiteSpace(fileRootPath))
throw new ArgumentNullException("fileRootPath", "fileRootPath is null"); FileRootPath = fileRootPath;
BlockRootPath = fileRootPath + "/blocktmp/";
}
/// <summary>
/// 块文件存储根路径
/// </summary>
private string BlockRootPath { get; set; } /// <summary>
/// 文件存储根路径
/// </summary>
public string FileRootPath { get; set; } /// <summary>
/// 分块上传
/// </summary>
public UploadResult Upload(string uploadId, int blockCount, int currIndex, string fileName, HttpPostedFileBase file)
{
try
{
if (file == null)
return new UploadResult { Msg = "请选择文件~" };
if (blockCount < )
return new UploadResult { Msg = "块数量不能小于1~" };
if (currIndex < )
return new UploadResult { Msg = "块数量小于0~" };
if (string.IsNullOrWhiteSpace(uploadId) && currIndex > )
return new UploadResult { Msg = "上传编号为空~" }; var result = new UploadResult { Code = , Msg = "上传成功~" }; //首次上传需创建上传编号
if (string.IsNullOrWhiteSpace(uploadId) || uploadId.Equals("undefind"))
uploadId = GenerateUploadId(); result.UploadID = uploadId; #region ==块处理== //块文件名称
var blockName = $"{uploadId}_{currIndex}.block";
//块文件目录路径
var blockPath = Path.Combine(BlockRootPath, uploadId);
//块文件目录对象
DirectoryInfo blockDirectoryInfo = Directory.Exists(blockPath) ? new DirectoryInfo(blockPath) : Directory.CreateDirectory(blockPath);
//块文件完整路径
var blockFullPath = Path.Combine(blockPath, blockName);
if (File.Exists(blockFullPath))
{
//块已上传,不做失败处理
return new UploadResult { Code = , Msg = "该文件块已上传~" };
} file.SaveAs(blockFullPath); #endregion #region ==块合并处理== //判断块文件是否已将上传完,上传完合并文件
if (blockDirectoryInfo.GetFiles().Count().Equals(blockCount))
{
var timestamp = DateTime.Now.ToString("yyyMMdd");
fileName = uploadId + "." + GetExtension(fileName);
var filePath = Path.Combine(FileRootPath, timestamp);
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
//完整文件存储路径
var fileFullPath = Path.Combine(filePath, fileName);
using (var fs = new FileStream(fileFullPath, FileMode.Create))
{
for (var i = ; i <= blockCount; i++)
{
var path = Path.Combine(blockPath, $"{uploadId}_{i}.block");
var bytes = File.ReadAllBytes(path);
fs.Write(bytes, , bytes.Length);
}
Directory.Delete(blockPath, true); result.FileInfo = new UploadFileInfo
{
FileName = fileName,
FilePath = Path.Combine(timestamp, fileName)
};
}
} return result;
#endregion
}
catch (Exception ex)
{
return new UploadResult { Msg = ex.Message };
}
} /// <summary>
/// 生成上传唯一编号
/// </summary>
/// <returns></returns>
public string GenerateUploadId()
{
var guid = Guid.NewGuid().ToString();
return guid.Replace("-", "");
} /// <summary>
/// 获取文件扩展名
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string GetExtension(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName) || fileName.IndexOf(".") < )
{
return string.Empty;
}
var arr = fileName.Split('.');
return arr[arr.Length - ];
}
}
/// <summary>
/// 文件上传结果
/// </summary>
public class UploadResult
{
/// <summary>
/// 状态码 0失败 1成功
/// </summary>
public int Code { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 上传编号,唯一
/// </summary>
public string UploadID { get; set; }
/// <summary>
/// 文件保存信息
/// </summary>
public UploadFileInfo FileInfo { get; set; } }
public class UploadFileInfo
{
/// <summary>
/// 文件保存名称
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 文件保存路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 文件MD5值
/// </summary>
public string MD5 { get; set; }
}
}

UploadHelper

  Controller代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace UploadTest.Controllers
{
[RoutePrefix("upload")]
public class UploadController : Controller
{
[Route]
[HttpGet]
public ActionResult Index()
{
return View();
}
[Route]
[HttpPost]
public ActionResult Upload(string uploadId,int total,int index,string fileName)
{
var helper = new UploadHelper("D:\\Upload");
var result = helper.Upload(uploadId, total, index, fileName, Request.Files[]); return Json(result);
}
}
}

使用HTML5 FormData对象实现大文件分块上传(断点上传)功能的更多相关文章

  1. php大文件分块上传断点续传demo

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

  2. .Net之使用Jquery Ajax通过FormData对象异步提交图片文件到服务端保存并返回保存的图片路径

    前言: 首先对于图片上传而言,在我们的项目开发中可以说出现的频率是相当的高的.这篇文章中,我将要描述的是在我们.Net中如何使用Jquery Ajax通过FormData对象异步提交图片文件到后台保存 ...

  3. JS原生上传大文件显示进度条-php上传文件

    JS原生上传大文件显示进度条-php上传文件 在php.ini修改需要的大小: upload_max_filesize = 8M    post_max_size = 10M    memory_li ...

  4. 使用PHP和HTML5 FormData实现无刷新文件上传教程

    无刷新文件上传是一个常见而又有点复杂的问题,常见的解决方案是构造 iframe 方式实现. 在 HTML5 中提供了一个 FormData 对象 API,通过 FormData 可以方便地构造一个表单 ...

  5. 利用blob对象实现大文件分片上传

    首先说分片上传,我们在进行文件上传的时候,因为服务器的限制,会限制每一次上传到服务器的文件大小不会很大,这个时候我们就需要把一个需要上传的文件进行切割,然后分别进行上传到服务器. 假如需要做到这一步, ...

  6. js大文件分块上传断点续传demo

    文件夹上传:从前端到后端 文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹. ...

  7. HTML5 FormData对象

    利用FormData对象,你可以使用一系列的键值对来模拟一个完整的表单,然后使用XMLHttpRequest发送这个"表单". 创建一个FormData对象 你可以先创建一个空的F ...

  8. java大文件分块上传断点续传demo

    第一点:Java代码实现文件上传 FormFile file = manform.getFile(); String newfileName = null; String newpathname =  ...

  9. springboot集成websocket实现大文件分块上传

    遇到一个上传文件的问题,老大说使用http太慢了,因为http包含大量的请求头,刚好项目本身又集成了websocket,想着就用websocket来做文件上传. 相关技术 springboot web ...

随机推荐

  1. JAVA下JSON的类型输出及使用

    JSON类型的输出: import java.util.ArrayList; import java.util.HashMap; import net.sf.json.JSONArray; impor ...

  2. [1] 插件架构(PLUG-IN)

    网上的一种比较好对插件的定义是:插件(Plug-in,又称addin.add-in.addon或add-on,又译外挂)也称为扩展,是一种遵循一定规范的应用程序接口编写出来的程序,主要是用来扩展软件功 ...

  3. JAVAEE学习路线分享

    今天把我的教学经验分享给大家.适合大多数人的学习路线.注:目前作者已经转行做java培训. 首先是培养兴趣.先开始学习HTML知识.也就是做网页,从这里开始比较简单,就是几个标签单词需要记住. 接着开 ...

  4. java数组降序排序之冒泡排序

    import java.util.Arrays;//必须加载 class Demo{ public static void main(String []args){ int[] arr={3,54,4 ...

  5. 增广拉格朗日乘子法(Augmented Lagrange Method)

    转载自:增广拉格朗日乘子法(Augmented Lagrange Method) 增广拉格朗日乘子法的作用是用来解决等式约束下的优化问题, 假定需要求解的问题如下: minimize f(X) s.t ...

  6. eclipse从SVN检出项目之后,项目出错

    今天公司把我分配到另一个项目组工作,然后下午使用SVN检出项目,出了问题 1.从SVN检出项目之后,要导入jar包.结果右键项目找不到Build Path,问了大牛才知道是这里的问题,一共四个步骤解决 ...

  7. Java基础(4)-数组

    java数组 public class ArrayKnowledge { @SuppressWarnings("unused") public static void main(S ...

  8. js 实现图片压缩并转换成base64(data:image/jpeg;base64)格式

    <!DOCTYPE html> <html> <head> <!--by 0o晓月メ http://www.cnblogs.com/final-elysion ...

  9. 简单总结一下 XSS

    你听说过XSS吗? XSS(Cross-site scripting, 跨站脚本)是一种网站应用程序的安全漏洞攻击,是代码注入的一种. 研究表明,最近几年 XSS 已经超过 "缓冲区溢出&q ...

  10. MySQL(二)--事务与视图

    一.事务 1.提交 2.回滚 3.ACID特性 二.视图 1.创建视图 2.删除视图 3.更新视图 4.使用视图 三.子查询 1. 使用子查询 2. 标量子查询 3. 关联子查询 一.事务 在 RDB ...