傳大的附件分為兩種情況,
第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小時內與您取得聯系。