关键词:
〝 古人学问遗无力,少壮功夫老始成 〞
一文搞懂分片上传和断点续传,对于做过文件上传的小伙伴对于这两个名词并不太陌生,而在上传大文件的业务中,这两种上传方式是经常被用到的,但是很多小白对这两种上传的方法的用法还是有点模糊,如果这篇文章能给你带来一点帮助,希望给飞兔小哥哥一键三连,表示支持,谢谢各位小伙伴们。
目录
一、什么是分片上传、断点续传
- 分片上传:将一个文件切割为一系列特定大小的小数据片,分别将这些小数据片分别上传到服务端,全部上传完后再在服务端将这些小数据片合并成为一个完整的资源。
- 断点续传:在分片上传的过程中,如果因为系统崩溃或者网络中断等异常因素导致上传中断,这时候客户端需要记录上传的进度。在之后支持再次上传时,可以继续从上次上传中断的地方进行继续上传
- 在网络不好,文件很大的情况下可以采用分片上传
- 而因为网络崩溃或者系统中断,可以采用断点续传
二、项目地址
- 该项目已经传到github和gitee上,欢迎大家fork、star、watch三连支持
- github项目地址:https://github.com/autofelix/autofelix-javascript-wiki/tree/master/fcup
- gitee项目地址:https://gitee.com/autofelix/autofelix-javascript-wiki/tree/master/fcup
三、分片上传实战
- 将完整视频切成每一个小片
- 这里我们使用的是jquery.fcup官方切片库
- 完整源代码都在上面的项目地址中
- 前端我们只要引入该切片库,进行以下简单的配置即可
$.fcup(
upId: 'upid', //上传dom的id
upShardSize: '1', //切片大小,(单次上传最大值)单位M,默认2M
upMaxSize: '200', //上传文件大小,单位M,不设置不限制
upUrl: 'fcup.php', //文件上传接口
upType: 'jpg,png,jpeg,gif,mp4', //上传类型检测,用,号分割
//接口返回结果回调,根据结果返回的数据来进行判断,可以返回字符串或者json来进行判断处理
upCallBack: function (res)
var status = res.status;
var msg = res.msg;
// 已上传完成
if (res.status == 2)
console.log(msg);
// 还在上传中
if (status == 1)
console.log(msg);
// 接口返回错误
if (status == 0)
// 停止上传并且提示信息
$.upStop(msg);
,
// 上传过程监听,可以根据当前执行的进度值来改变进度条
upEvent: function (num)
// num的值是上传的进度,从1到100
console.log('当前上传进度:' + num + '%');
,
// 发生错误后的处理
upStop: function (errmsg)
// 这里只是简单的alert一下结果,可以使用其它的弹窗提醒插件
// alert(errmsg);
,
// 开始上传前的处理和回调,比如进度条初始化等
upStart: function ()
alert('开始上传');
);
四、如何进行切片
- 在切片库中我们可以看到以下流程
- 第一步:加载配置、获取dom元素、执行fcup_addFileInput方法
- 第二步:其实就是获取上传dom元素的位置然后在该位置加一个透明的文件上传按钮,这样用户在点击dom元素的时候,其实点击的是这个透明的文件上传按钮,弹出上传文件的选项
- 第三步:第二步其实已经初始化完毕,后续操作需要用户点击,触发fcup_upload上传方法
- 第四步:进行切片上传核心代码,设置分片大小、切片,递归通过ajax进行上传
//这是第一步
fcup: function (config)
jQuery.extend(config);
if (jQuery.upId && jQuery.upUrl)
jQuery.domHtml = jQuery('#' + jQuery.upId).html();
jQuery.fcup_addFileInput();
,
//这是第二步
fcup_addFileInput: function ()
jQuery.upInputId = jQuery.upId + '_input';
var C = jQuery('#' + jQuery.upId).attr("class");
var X = jQuery('#' + jQuery.upId).position().top;
var Y = jQuery('#' + jQuery.upId).position().left;
var W = jQuery('#' + jQuery.upId).innerWidth();
var H = jQuery('#' + jQuery.upId).innerHeight();
var html = jQuery.domHtml;
if (C)
html += '<input type="file" id="' + jQuery.upInputId + '" class="' + C + '" onchange="jQuery.fcup_upload()" style="position:absolute;left:' + Y + 'px;top:' + X + 'px;opacity:0;z-index:9999;width:' + W + 'px;height:' + H + 'px;">';
else
html += '<input type="file" id="' + jQuery.upInputId + '" onchange="jQuery.fcup_upload()" style="position:absolute;left:' + Y + 'px;top:' + X + 'px;opacity:0;z-index:9999;width:' + W + 'px;height:' + H + 'px;">';
jQuery('#' + jQuery.upId).html(html);
,
//这是第三步
fcup_upload: function ()
var result = '';
jQuery.upError = '';
var file = jQuery('#' + jQuery.upInputId)[0].files[0];
if (!file)
return false;
if (typeof jQuery.upStart == 'function')
jQuery.upStart();
name = file.name;
size = file.size;
index1 = name.lastIndexOf(".");
if (!jQuery.upShardSize)
jQuery.upShardSize = 2;
var fileMD5 = jQuery.get_file_md5(file);
var index2 = name.length,
suffix = name.substring(index1 + 1, index2),
shardSize = jQuery.upShardSize * 1024 * 1024,
succeed = 0,
shardCount = Math.ceil(size / shardSize);
if (jQuery.upType)
uptype = jQuery.upType.split(",");
if (jQuery.inArray(suffix, uptype) == -1)
jQuery.upError = '不允许上传的文件类型-' + suffix;
if (jQuery.upMaxSize)
if (!jQuery.fcup_limitFileSize(file, jQuery.upMaxSize + 'MB'))
jQuery.upError = '上传文件过大';
if (jQuery.upStatus() == false)
return false;
setInterval("jQuery.fcup_upFileInput();",500);
var re = [];
var start, end = 0;
for (var i = 0; i < shardCount; ++i)
re[i] = [];
start = i * shardSize,
end = Math.min(size, start + shardSize);
re[i]["file_data"] = file.slice(start, end);
re[i]["file_name"] = name;
re[i]["file_size"] = size; //文件大小
const URL = jQuery.upUrl;
var i2 = 0, i3 = 1, fcs = Array();
var xhr = new XMLHttpRequest();
function ajaxStack(stack)
if (jQuery.upStatus() == false)
return;
var form = new FormData();
if (stack[i2])
fcs = stack[i2];
form.append("file_data", fcs['file_data']);
form.append("file_name", fcs['file_name']);
form.append("file_size", fcs['file_size']);
form.append("file_md5", fileMD5);
form.append("file_total", shardCount);
form.append("file_index", i3);
xhr.open('POST', URL, true);
xhr.onload = function ()
ajaxStack(stack);
xhr.onreadystatechange = function ()
if (jQuery.upStatus() == false)
return;
if (xhr.readyState == 4 && xhr.status == 200)
var data = xhr.responseText ? eval('(' + xhr.responseText + ')') : '';
++succeed;
var cent = jQuery.fcup_getPercent(succeed, shardCount);
if (typeof jQuery.upEvent == 'function')
jQuery.upEvent(cent);
if (cent == 100)
setTimeout(function ()
if (typeof jQuery.upCallBack == 'function')
jQuery.upCallBack(data);
, 500);
else
if (typeof jQuery.upCallBack == 'function')
jQuery.upCallBack(data);
xhr.send(form);
i2++; i3++;
form.delete('file_data');
form.delete('file_name');
form.delete('file_size');
form.delete('file_md5');
form.delete('file_total');
form.delete('file_index');
ajaxStack(re);
re = null,
file = null;
,
//这是核心代码
for (var i = 0; i < shardCount; ++i)
re[i] = [];
start = i * shardSize,
end = Math.min(size, start + shardSize);
re[i]["file_data"] = file.slice(start, end);
re[i]["file_name"] = name;
re[i]["file_size"] = size; //文件大小
五、后端对分片的处理
- 因为每个分片的md5值是唯一的
- 所以可以通过md5值判断分片文件是否已经上传
- 如果已经上传可以直接跳过,否则进行分片的保存
- 通过索引和总数进行对比判断是否上传成功
- 上传成功的话,将分片进行合并成一个完整的文件
- 因为服务器内存的最大化,文件合并完毕就可以将分片删除清理
private function run($file)
//上传分片到分片目录
$shard_file = $file['file_md5'] . DIRECTORY_SEPARATOR . $file['file_index'];
//跳过重复文件
$result = file_exists($shard_file) ?: move_uploaded_file($file['file_data']['tmp_name'], $shard_file);
if ($this->isFinish($file) && $result)
try
for ($i = 0; $i < $file['file_total']; $i++)
$fileIndex = $i + 1;
$blob = file_get_contents($file['file_md5'] . DIRECTORY_SEPARATOR . $fileIndex);
file_put_contents($this->saveRoot . DIRECTORY_SEPARATOR . $file['file_name'], $blob, FILE_APPEND);
//删除分片文件
array_map('unlink', glob("$file['file_md5']/$fileIndex"));
//删除分片文件夹
@rmdir($file['file_md5']);
$this->jsonBack([
'status' => static::UPLOAD_FINISH,
'msg' => '上传完成'
]);
catch (Exception $e)
$this->jsonBack([
'status' => static::UPLOAD_ERROR,
'msg' => $e->getMessage()
]);
else
if ($result)
$this->jsonBack([
'status' => static::UPLOAD_START,
'msg' => '正在上传:' . $file['file_index'] . '/' . $file['file_total']
]);
else
$this->jsonBack([
'status' => static::UPLOAD_ERROR,
'msg' => '上传错误,请重新上传'
]);
六、断点续传
- 其实在上面流程已经可以显示出来了
- 上传的时候有个索引值,告诉你,当前已经传到哪一个分片了
- 如果系统崩溃,导致上传断开,可以判断这个索引值,上传过的可以略过,进行后续的上传
前端+后端实现分片上传(断点续传/极速秒传)(代码片段)
...大文件/视频前后端(java)代码前端+后端实现分片上传(断点续传/极速秒传)前端slice分片上传,后端用表记录分片索引和分片大小和分片总数,当接受完最后一个分片(分片索引等于分片总数... 查看详情
springboot实现分片上传断点续传大文件极速秒传-备忘(代码片段)
...传体验呢,答案有的,就是下边要介绍的几种上传方式1.分片上传1.1什么是分片上传 分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为Part)来进行分别上传,上传完之后再由服... 查看详情
项目难点——断点续传分片上传(代码片段)
项目难点——【2】断点续传、分片上传1文件分片在网络请求中,如果我们有时是上传大文件,可能由于网络原因,导致上传断断续续,很难一次性上传成功,那么这个时候我们就需要将大文件分块,分成... 查看详情
ios大文件分片上传和断点续传
总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块)... 查看详情
超大文件上传和断点续传的源代码
总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块)... 查看详情
实战:5分钟搞懂okhttp断点上传(代码片段)
1、前言经常会有同学问:文件的断点上传如何实现?断点上传/下载,这是在客户端经常遇到的场景,当我们需要上传或下载一个大文件时,都会考虑使用断点续传的方式。断点上传相较于断点下载来说,... 查看详情
超大文件上传和断点续传的源代码
总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块)... 查看详情
springboot分片上传断点续传大文件极速秒传功能,这篇都帮你搞定!(典藏版)...(代码片段)
...呢,答案有的,就是下边要介绍的几种上传方式1.分片上传1.1什么是分片上传分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为Part)来进行分别上传,... 查看详情
jsp利用webuploader实现超大文件分片上传断点续传
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。第一步:前端修改由于项目使用的是BJUI前端框架,并... 查看详情
阿里云oss文件上传(分片上传断点续传)前后端实现(代码片段)
转载地址:https://segmentfault.com/a/1190000020963346 关于阿里云OSS的介绍请参考官方文档:阿里云OSS。出于账号安全的考虑,前端使用OSS服务需要走临时授权,即拿一个临时凭证(STSToken)去调用aliyun... 查看详情
阿里云oss文件上传(分片上传断点续传)前后端实现(代码片段)
转载地址:https://segmentfault.com/a/1190000020963346 关于阿里云OSS的介绍请参考官方文档:阿里云OSS。出于账号安全的考虑,前端使用OSS服务需要走临时授权,即拿一个临时凭证(STSToken)去调用aliyun... 查看详情
前端实现大文件上传分片上传断点续传
总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块)... 查看详情
大文件分片上传,断点续传,秒传实现
...PHP的上传文件限制不宜过大,一般5M左右为好;2,大文件分片,一片一片的传到服务端,再由 查看详情
csharp文件分片上传,断点续传
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。 第一步:前端修改由于项目使用的是BJUI前端框架,... 查看详情
vue超大文件上传解决方案:分片断点上传
...所必须直面的。本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路。实现文件夹上传,要求:服务端保留层级结构,支持10w级别的文件夹上传。大文件上传及断点续传,要求:支持50G级的单个文... 查看详情
面试官:请你实现一个大文件上传和断点续传(代码片段)
...一段时间整理了下思路,那么究竟该如何实现一个大文件上传,以及在上传中如何实现断点续传的功能呢?本文将从零搭建前端和服务端,实现一个大文件上传和断点续 查看详情
java如何实现大文件分片上传,断点续传和秒传
Java如何实现大文件分片上传,断点续传和秒传引言概念秒传1、什么是秒传2、实现秒传常见做法分片上传1、什么是分片上传2、分片上传的场景断点续传1、什么是断点续传2、应用场景3、实现断点续传的核心逻辑实现思路前置知识... 查看详情
分块上传和断点续传(代码片段)
分块上传和断点续传两个概念分块上传:文件切成多块,独立传输,上传完成后合并断点续传:传输暂停或异常中断后,可基于原来进度重传几点说明:1、小文件不建议分块上传2、可以并行上传,并... 查看详情