传大的附件分为两种情况,
第2种使用分片上传
优势:可以突破服务器上传大小的限制,可以web存储上传到哪一块了,在浏览器关闭或者刷新的情况下可以断点续传;
劣势:上传速度慢,在我本地电脑测试,200M的文件,改变配置按照正常方式上传大约需要12到15秒,但是使用第2种分片上传,大约需要40多秒,也就是所需时间是正常上传的3倍,我测试了for循环同时上传几个碎片,电脑直接很卡,点击别的浏览器或者文件夹之类的全部是没有响应,所以放弃了使用循环同时上传多个;
如果上传大的文件实现进度条是很有必要的,否则用户看不到进度会等得不耐烦了。
小的文件只需要2秒左右,是否有进度条没有关系。
第一种,在可以改变服务器配置的前提下
图1 带进度条文件上传
1、配置php.ini
如果上传的文件比较大,以上4点都需要修改,特别是第2点,尽可能配置,否则上传最后会比较慢。
2、iis上传大小限制,可以在web.config直接修改,加入以下代码
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
<requestLimits maxAllowedContentLength="1073741824" /> 这里是限制的大小,默认大小忘记了,我这里设置的是可以上传1G进行的测试。
3、nginx上传大小限制
我开始想把这些加到location / {}里边,提示错误client_header_timeout不允许放到里边,所以全部加到外边了,也就是server {}里边;
注意下第6点,如果不配置,nginx上传文件会存到缓存,然后再一点一点传到upload_tmp_dir的目录下,导致上传所需时间是iis的2倍。
4、html代码
<tr class=''>
<td width="90" align="right" rowspan='2'>超大附件</td>
<td>
<div class='jdfull '><div class='jdperc'></div></div>
<div class='jdtis '>0%</div>
<input type='file' id="down_bfule_tpfile" class='inpMain layui-inpu' name='' size='30'><button type='button' class='layui-btn submitpfile' >上传</button> </td>
</tr>
<tr class=''>
<td>
<input type='text' class='inpMain' placeholder='不限大小' style='width:calc(100% - 20px);' value='' name='down_bfule' id="down_bfule" ></td>
</tr>
5、css代码 用来设置进度条
/*进度条*/
.jdfull{width:calc(100%);height:20px;background:#FFF;margin-bottom:10px;border-radius:10px;border:1px solid #DDD;}
.jdperc{height:20px;background:#5FB878;width:0px;border-radius:10px;}
.jdtis{margin-bottom:10px;}
6、js代码(jquery使用监听progress实现进度条功能)
$(".submitpfile").click(function() {
var fileext=['rar','zip','pdf'];
var formData = new FormData();
formData.append("file", $("#down_bfule_tpfile").get(0).files[0]);
if (!$("#down_bfule_tpfile").get(0).files[0]) {
alert("请选择要上传的文件!");
return false
};
//判断扩展名 是否支持上传
var patharr = $("#down_bfule_tpfile").get(0).files[0].name.split(".");
//上传文件扩展名转小写,ZIP zip 2个是同一个文件
var ext = patharr[patharr.length - 1].toLowerCase();
if (fileext.indexOf(ext) < 0) {
alert('只支持' + fileext.join(','));
return false;
}
$.ajax({
url: '处理图片上传的url',
data: formData,
type: "post",
dataType: "json",
contentType: false,
processData: false,
//监听progress 实现上传进度条
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress',
function(e) {
console.log(e);
//百分比取整
var progressRate = parseInt((e.loaded / e.total) * 100);
$('.jdfull .jdperc').css('width', progressRate + "%");
$('.jdtis').html(progressRate + "%")
});
return xhr
},
/*进度条结束*/
success: function(result) {
if (result.error == "0000") {
console.log(result.msg);
//上传完成以后文件地址赋值给文本框,用于表单提交
$("#down_bfule").val(result.msg);
} else {
//错误信息提示
alert(result.msg);
return false
}
//上传框初始化
var objFile = document.getElementById("down_bfule_tpfile");
objFile.outerHTML = objFile.outerHTML.replace(/(value=\").+\"/i, '$1"')
}
})
})
7、后端php处理程序
foreach($_FILES as $k=>$v){
$v['name']//文件名称
$v['size']//文件大小
$v["tmp_name"]//临时文件名包含了物理路径E:\temp\文件名
move_uploaded_file($v["tmp_name"],'文件存放路径(物理路径+文件名)')
}
第二种,不能改变服务器的配置使用分片上传
图2 进度条显示多少片
html,css不变,只是改变js,下面是用到的js代码
代码1:点击事件
$(".submitpfile").click(function() {
var fileext=['rar','zip','pdf'];//支持格式
var ranksize=1024*1024;//分片每次上传的大小 1M
if (!$("#down_bfule_tpfile").get(0).files[0]) {
alert("请选择要上传的文件!");
return false
};
var patharr = $("#down_bfule_tpfile").get(0).files[0].name.split(".");
var ext = patharr[patharr.length - 1].toLowerCase();
if (fileext.indexOf(ext) < 0) {
alert('只支持' + fileext.join(','));
return false
}
var size = $("#down_bfule_tpfile").get(0).files[0].size;
var start=true;//是否从第一个开始上传
var localname=$("#down_bfule_tpfile").get(0).files[0].name;
/*
使用localStorage 文件名作文变量存储
存储大小,还有上传了多少片
文件名存放 判断大小 如果大小也和上传的文件相同判断为同一个文件
如果用户把文件名改成了上传过的,不加判断会造成上传文件错误
window.localStorage.getItem 获取存储的数据
window.localStorage.setItem 设置存储的数据 key value
window.localStorage.removeItem 移除存储的数据
JSON.parse 字符串转成json格式
*/
if(JSON.parse(window.localStorage.getItem(localname))){
var localsize=JSON.parse(window.localStorage.getItem(localname)).localsize;
var ranknum=JSON.parse(window.localStorage.getItem(localname)).ranknum;
if(size==localsize){
//已经上传过 但是没有上传完,中断了
start=false;
}
}
if(start==true){
//第一片开始上传
uploadtp(1);
}else{
//存储的下一片开始上传
uploadtp(ranknum+1);
}
})
代码2:uploadtp方法
function uploadtp(m){
var size = $("#down_bfule_tpfile").get(0).files[0].size;
var formData = new FormData();
formData.append("filename", $("#down_bfule_tpfile").get(0).files[0].name);
formData.append("size", size);
//Math.ceil 向上取整 获得上传总得片数 例如:1.1 1.9 都会取整为2,和php的分页一个性质
rankcount=Math.ceil(size/ranksize);
/*
uptemp 用于存放 要上传大小 上传完多少片
uptemp['ranknum']=m; 上传完多少片
uptemp['localsize']=size; 上传文件总得大小,用于判断要上传的是否同一个文件
JSON.stringify 数组转成json字符串
*/
var uptemp={};
uptemp['ranknum']=m;
uptemp['localsize']=size;
window.localStorage.setItem($("#down_bfule_tpfile").get(0).files[0].name,JSON.stringify(uptemp));
/*存储完成*/
/*
$("#down_bfule_tpfile").get(0).files[0].slice 对选择的文件进行切割
(m-1)*ranksize 起始位置
m*ranksize 结束位置
*/
formData.append("photo", $("#down_bfule_tpfile").get(0).files[0].slice((m-1)*ranksize,m*ranksize));
$.ajax({
url: "处理上传的url",
data: formta,
type: "post",
dataType: "json",
contentType: false,
processData: false,
/*
进度条开始
这是一种竖线方式 监听progress,监听每一片的上传进度
*/
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress',
function(e) {
console.log(e);
var progressRate = parseInt((e.loaded / e.total) * 100);
$('.jdfull .jdperc').css('width', progressRate + "%");
$('.jdtis').html("总共:<span style='color:red'>"+rankcount+"</span>片,当前:第<span style='color:red'>"+m+"</span>片"+progressRate + "%")
});
return xhr
},
/*进度条结束*/
success: function(result) {
if (result.error == "0000") {
$('.jdtis').html("全部上传完成!");
//上传完成,清除以前的分片存储
window.localStorage.removeItem($("#down_bfule_tpfile").get(0).files[0].name);
var objFile = document.getElementById("down_bfule_tpfile");
objFile.outerHTML = objFile.outerHTML.replace(/(value=\").+\"/i, '$1"');
$("#down_bfule").val(result.msg)
} else if(result.error == "0001") {
//0001文件没有上传完 需要继续上传
uploadtp(m+1);
}else{
//php处理返回的错误提示 比如长时间没有刷新页面,导致已经退出登陆了
alert(result.msg);
return false
}
}
/*
第2种 去掉上边进度条开始 到结束的代码,使用下面的success 代替上边的success
根据上传了多少片除以总数 显示当前的百分比 var progressRate=parseInt((m / rankcount) * 100);
*/
/*
success: function(result) {
if (result.error == "0000") {
var progressRate=100;
$('.jdfull .jdperc').css('width', progressRate + "%");
$('.jdtis').html("全部上传完成!");
window.localStorage.removeItem($("#down_bfule_tpfile").get(0).files[0].name);
var objFile = document.getElementById("down_bfule_tpfile");
objFile.outerHTML = objFile.outerHTML.replace(/(value=\").+\"/i, '$1"');
$("#down_bfule").val(result.msg)
} else if(result.error == "0001") {
var progressRate=parseInt((m / rankcount) * 100);
$('.jdfull .jdperc').css('width', progressRate + "%");
$('.jdtis').html(progressRate + "%");
//0001文件没有上传完 需要继续上传
uploadtp(m+1);
}else{
//php处理返回的错误提示 比如长时间没有刷新页面,导致已经退出登陆了
alert(result.msg);
return false
}
}
*/
})
}
php后端处理程序
$filename=input('post.filename');//原始文件名
$size=input('post.size');//原始文件大小
//创建存放的文件夹
foreach($_FILES as $k=>$v){
//$v["tmp_name"]临时文件 含路径
$images_dir = '/public/upload/file/'.date("Ymd")."/";
if (!file_exists(ROOT_PATH."".$images_dir)) {
mkdir(ROOT_PATH."".$images_dir,0777);
}
$name = explode(".", $filename); //将上传前的文件以“.”分开取得文件类型 支持png jpg gif
$imgtype=strtolower($name[count($name)-1]);//类型转成小写
$newname=date("YmdHis".rand(10000,99999)).".".$imgtype;//新的文件名
//file_put_contents 追加 注意有FILE_APPEND,不加的话会覆盖原来的
//file_get_contents读取内容
file_put_contents(ROOT_PATH.$images_dir.$filename,file_get_contents($v["tmp_name"]),FILE_APPEND);
//判断大小 是否已经上传完成
if(filesize(ROOT_PATH.$images_dir.$filename)>=$size){
rename(ROOT_PATH.$images_dir.$filename,ROOT_PATH.$images_dir.$newname);
exit( json_encode(array('error'=>'0000','msg'=>$images_dir.$newname),JSON_UNESCAPED_UNICODE));
}else{
exit( json_encode(array('error'=>'0001'),JSON_UNESCAPED_UNICODE));
}
}
说明:
nginx上传文件很慢
处理办法:关闭 fastcgi_request_buffering,如果不关闭,上传所需时间至少是iis的2倍;
具体操作:编辑nginx.conf,
server {
fastcgi_request_buffering off;
}
.说明:
推荐指数:★★★★
通俗易懂,小白一看就会,高手请飘过。
学python也是需要懂一点Html、Css、JavaScript的基础知识的。
建议使用vscode编辑器。
2.效果图1
3.代码:保存为html,用浏览器打开即可。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>圆形百分比进度条效果</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.bg{
width: 200px;
height: 200px;
border-radius: 100%;
background: #ccc;
position: relative;
margin: 20px auto;
}
.circle-right, .circle-left, .mask-right, .mask-left{
width: 200px;
height: 200px;
border-radius: 100%;
position: absolute;
top: 0;
left: 0;
}
.circle-right, .circle-left{
background: skyblue;
}
.mask-right, .mask-left{
background: #ccc;
}
.circle-right, .mask-right{
clip: rect(0,200px,200px,100px);
}
.circle-left, .mask-left{
clip: rect(0,100px,200px,0);
}
.text{
width: 160px;
height: 160px;
line-height: 160px;
text-align: center;
font-size: 34px;
color: deepskyblue;
border-radius: 100%;
background: #fff;
position: absolute;
top: 20px;
left: 20px;
}
</style>
</head>
<body>
<div class="bg">
<div class="circle-right"></div>
<!--100%是显示百分数,动态显示由0~100-->
<div class="text">100%</div>
</div>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
//获取百分比值
var num = parseInt($('.text').html());
//通过计时器来显示过渡的百分比进度
var temp = 0;
var timer = setInterval(function(){
calculate(temp);
//清除计时器结束该方法调用
if(temp == num){
clearInterval(timer);
}
temp++;
},30)
//改变页面显示百分比
function calculate(value){
//改变页面显示的值
$('.text').html(value + '%');
//清除上次调用该方法残留的效果
$('.circle-left').remove();
$('.mask-right').remove();
//当百分比小于等于50
if(value <= 50){
var html = '';
html += '<div class="mask-right" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
//元素里添加子元素
$('.circle-right').append(html);
}else{
value -= 50;
var html = '';
html += '<div class="circle-left">';
html += '<div class="mask-left" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
html += '</div>';
//元素后添加元素
$('.circle-right').after(html);
}
}
})
</script>
</body>
</html>
4.拆分法:把一个含有css和js(JavaScript)的html,拆掉三个文件,一个叫cirbar1.html,另外的叫:cirbar1.css和cirbar1.js文件,放在同一个文件夹内。这是./的意思,也可以指定文件夹。
4.1 cirbar1.html的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>圆形百分比进度条效果v2</title>
<!--如果是style type="text/css"这种直接在html中设置css,注意起始是*,不是点-->
<!--style type="text/css"-->
<link href="./cirbar1.css" rel="stylesheet" />
</head>
<body>
<div class="bg">
<div class="circle-right"></div>
<div class="text">100%</div>
</div>
<!--这个外部js文件=jquery.min.js,不能少,否则不能动了-->
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"--></script>
<!--同样的,把写在html的js,新建一个cirbar1.js,复制下去,保存,这样子简洁很多-->
<!--script type="text/javascript"-->
<script src="./cirbar1.js"></script>
</body>
</html>
4.2 cirbar1.css的代码:
*{
margin: 0;
padding: 0;
}
.bg{
width: 200px;
height: 200px;
border-radius: 100%;
background: #ccc;
position: relative;
margin: 20px auto;
}
.circle-right, .circle-left, .mask-right, .mask-left{
width: 200px;
height: 200px;
border-radius: 100%;
position: absolute;
top: 0;
left: 0;
}
.circle-right, .circle-left{
background: skyblue;
}
.mask-right, .mask-left{
background: #ccc;
}
.circle-right, .mask-right{
clip: rect(0,200px,200px,100px);
}
.circle-left, .mask-left{
clip: rect(0,100px,200px,0);
}
.text{
width: 160px;
height: 160px;
line-height: 160px;
text-align: center;
font-size: 34px;
color: deepskyblue;
border-radius: 100%;
background: #fff;
position: absolute;
top: 20px;
left: 20px;
}
4.3 cirbar1.js的代码:
$(function(){
//获取百分比值
var num = parseInt($('.text').html());
//通过计时器来显示过渡的百分比进度
var temp = 0;
var timer = setInterval(function(){
calculate(temp);
//清除计时器结束该方法调用
if(temp == num){
clearInterval(timer);
}
temp++;
},30)
//改变页面显示百分比
function calculate(value){
//改变页面显示的值
$('.text').html(value + '%');
//清除上次调用该方法残留的效果
$('.circle-left').remove();
$('.mask-right').remove();
//当百分比小于等于50
if(value <= 50){
var html = '';
html += '<div class="mask-right" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
//元素里添加子元素
$('.circle-right').append(html);
}else{
value -= 50;
var html = '';
html += '<div class="circle-left">';
html += '<div class="mask-left" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
html += '</div>';
//元素后添加元素
$('.circle-right').after(html);
}
}
})
==============================
再来一个,不用外部js文件的圆形进度条
顺带回顾一下相关知识。
==============================
5.效果图
6.三个文件,放在同一个文件夹中
6.1 cirbar.html代码:
<!--第1步---声明html5-->
<!DOCTYPE html>
<!--第2步---html大框架-->
<html lang="en">
<!--第2-1步---head部分-->
<head>
<!--第2-1-1步---meta部分:声明字符编码格式:utf-8-->
<!--注意与python的第一行声明一样:# -*- coding: utf-8 -*-->
<meta charset="utf-8" />
<!--第2-1-2步---标题名称-->
<title>圆形进度条v1</title>
<!--注意:./代表同一个文件夹下,也就是css和js文件与本html文件放在同一个文件夹下-->
<!--第2-1-3步---导入css文件-->
<link href="./cirbar.css" rel="stylesheet" />
</head>
<!--第2-2步---body部分-->
<body>
<!--第2-2-1步---定义画布部分,注意没有逗号隔开,大小设置-->
<canvas class="canvas" id="canvas" width="400" height="400"></canvas>
<!--第2-2-2步---导入js文件部分-->
<script src="./cirbar.js"></script>
<!--注意收尾-->
</body>
<!--注意收尾-->
</html>
6.2 cirbar.css代码:
.canvas {
/*画布的背景颜色设置为:黑色*/
background:#303030;
}
6.3 cirbar.js代码:
window.onload = function () {
var canvas = document.getElementById('canvas'), //获取canvas元素
context = canvas.getContext('2d'), //获取画图环境,指明为2d
centerX = canvas.width / 2, //Canvas中心点x轴坐标
centerY = canvas.height / 2, //Canvas中心点y轴坐标
rad = Math.PI * 2 / 100, //将360度分成100份,那么每一份就是rad度
speed = 0.1; //加载的快慢就靠它了
//绘制红色外圈
function blueCircle(n) {
context.save();
context.strokeStyle = " #1E90FF"; //随百分数转动的外圈的颜色为蓝色
context.lineWidth = 3; //设置线宽
context.beginPath(); //路径开始
//注意-为顺时针,+为逆时针
//用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)
//context.arc(centerX, centerY, 50, Math.PI / 2, Math.PI / 2 - n * rad, false);
context.arc(centerX, centerY, 50, -Math.PI / 2, -(Math.PI / 2 - n * rad), false);
context.stroke(); //绘制
context.closePath(); //路径结束
context.restore();
}
//绘制白色外圈,初始的白色外圈
function whiteCircle() {
context.save();
context.beginPath();
// 下面百分数的字体颜色设置后上面的外圈的颜色竟然保持一样
//context.strokeStyle = "#F8F8FF";
context.arc(centerX, centerY, 50, 0, Math.PI * 2, false);
context.stroke();
context.closePath();
context.restore();
}
//百分比文字绘制
function text(n) {
context.save(); //save和restore可以保证样式属性只运用于该段canvas元素
context.strokeStyle = "#7FFF00";//设置中间动态百分数的颜色
context.font = "25px Arial"; //设置字体大小和字体
context.textAlign = 'center';//字体水平居中
context.textBaseline = 'middle';//字体垂直居中
//绘制字体,并且指定位置
context.strokeText(n.toFixed(0) + "%", centerX, centerY);
context.stroke(); //执行绘制
context.restore();
}
//循环获取
(function drawFrame() {
window.requestAnimationFrame(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
whiteCircle();
text(speed);
blueCircle(speed);
if (speed < 100) {
//1可从后台获取值,也是从0~100,step为1,代表速度
speed += 1;
}
}());
}
注意到6.3js文件与4.3js文件的区别了么?一个有:window.onload =,一个没有,且只有$和小括号,因为外部的就是文件定义了一部分功能。
UE项目中大文件切片上传实现秒传、断点续传的详细实现教程,VUE大文件切片上传,VUE大文件切片上传教程,VUE大文件切片上传视频,VUE大文件分片上传,VUE大文件切割上传,VUE大文件分段上传,VUE大文件分块上传,VUE大文件秒传,VUE大文件断点续传,VUE大文件切片加密上传,VUE大文件切片批量上传下载,
用户上传的文件比较大,有20G左右,直接用HTML传的话容易失败,服务器也容易出错,需要分片,分块,分割上传。也就是将一个大的文件分成若干个小文件块来上传,另外就是需要实现秒传功能和防重复功能,秒传就是用户如果上传过这个文件,那么直接在数据库中查找记录就行了,不用再上传一次,节省时间,实现的思路是对文件做MD5计算,将MD5值保存到数据库,算法可以用MD5,或者CRC,或者SHA1,这个随便哪个算法都行。
分片还需要支持断点续传,现在HTML5虽然提供了信息记录功能,但是只支持到了会话级,也就是用户不能关闭浏览器,也不能清空缓存。但是有的政府单位上传大文件,传了一半下班了,明天继续传,电脑一关结果进度信息就丢失了,这个是他们的一个痛点。
切片的话还有一点就是在服务器上合并,一个文件的所有分片数据上传完后需要在服务器端进行合并操作。
功能的话支持20G文件上传和续传,支持秒传,支持文件夹上传,支持在服务端保存文件夹层级结构,支持将文件夹层级结构信息保存到数据库中,支持下载时能够将文件夹层级结构下载下来,支持下载文件夹,下载文件夹支持断点续传,支持VUE2,VUE3,React,支持IE,Chrome和信创国产化环境,比如银河麒麟,统信UOS,龙芯,支持加密传输,包括加密上传,加密下载,加密算法支持国密SM4,支持云对象存储,比如华为云,阿里云,腾讯云,七牛云,AWS,MinIO,FastDFS,需要提供手机,QQ,微信,邮箱等联系方式,提供7*24小时技术支持,提供长期技术支持和维护服务,提供远程1对1技术指导,提供二次开发指导,提供文档教程,提供视频教程。
代码:https://gitee.com/xproer/up6-vue-cli
1.引入up6组件
2.配置接口地址
接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表
参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de
3.定义事件
源码工程文档:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra
源码报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl
控件源码下载:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc
*请认真填写需求信息,我们会在24小时内与您取得联系。