Vue項目使用Websocket大文件FileReader()切片上傳實例
大文件上傳,本地1.3G文件不到一分鐘上傳完畢
使用技術(shù)
- Vue框架
- WebSocket雙向傳輸
- FileReader讀取文件
封裝的WebSocket請求文件上傳方法,目前只支持單文件上傳,有研究出來多文件上傳,記得評論哦
upfile.js文件
//file.slice(起始字節(jié),終止字節(jié))與FileReader實現(xiàn)文件切片讀取 function PartFileReader(files, type, event) { this.files = files;//inputObj.files[0] this.type = type; //配置FileReader讀取文件的方法 this.event = event;//配置讀取文件時需要觸發(fā)的事件 this.total = files.size;//獲取文件大小 this.step = 1024 * 1024 * 10;//1MB(單片大小/一兆) this.loaded = 0; //文件當(dāng)前讀取進度 this.reader = new FileReader(); //實際讀取文件的FileReader對象實例 this.abort = this.reader.abort; //中斷文件讀?。梢酝ㄟ^中斷文件讀取事件保留切片數(shù)據(jù),實現(xiàn)下一次可以在原讀取位置繼續(xù)開始讀?。? this.readPartFile(this.loaded); //開啟讀取文件 this.bindEvent();//綁定FileReader文件讀取 } //給切片讀取對象原型上添加FileReader獲取讀取類型,開啟讀取文件 PartFileReader.prototype.readPartFile = function (start) { if (this.files.slice) { var file = this.files.slice(start, this.loaded + this.step); switch (this.type) { // 開始讀取指定的 Blob中的內(nèi)容,根據(jù)讀取方式不同,result最后返回的數(shù)據(jù)也不同 case 'readAsBinaryString' : // result屬性中將包含所讀取文件的原始二進制數(shù)據(jù)。 this.reader.readAsBinaryString(file); break; case 'readAsDataURL' : // result屬性中將包含一個data: URL 格式的 Base64 字符串以表示所讀取文件的內(nèi)容。 this.reader.readAsDataURL(file); break; case 'readAsArrayBuffer' : // result 屬性中保存的將是被讀取文件的 ArrayBuffer 數(shù)據(jù)對象。 this.reader.readAsArrayBuffer(file); break; case 'readAsText' : // 一旦完成,result屬性中將包含一個字符串以表示所讀取的文件內(nèi)容。 this.readAsText(file); break; } } } //給切片讀取對象原型上綁定FileReader對象事件 PartFileReader.prototype.bindEvent = function () { var self = this; this.reader.onloadstart = function (e) { // FileReader.onloadstart 該事件在讀取操作開始時觸發(fā)。 self.event.loadStart && self.event.loadStart.call(this, e); } this.reader.onprogress = function (e) { // FileReader.onprogress 該事件在讀取Blob時觸發(fā)。 self.event.progress && self.event.progress.call(this, e); } this.reader.onload = function (e) { // FileReader.onload 該事件在讀取操作完成時觸發(fā)。 // 切片讀取文件有別于非切片讀取,切片讀取的文件讀取狀態(tài)需要在每個切片讀取成功后再刷新讀取進度 self.loaded += e.loaded; self.event.load && self.event.load.call(this, e, self.loaded, self.total); if (self.loaded < self.total) { self.readPartFile(self.loaded); } } this.reader.onloadend = function (e) { // FileReader.onloadend 該事件在讀取操作結(jié)束時(要么成功,要么失?。┯|發(fā)。 self.event.loadend && self.event.loadend.call(this, e); } this.reader.onabort = function (e) { // FileReader.onabort 該事件在讀取操作被中斷時觸發(fā)。 self.event.abort && self.event.abort.call(this, e); } } function readFile(socket,file,obj) { console.log("文件",file); var reader = new PartFileReader(file, 'readAsArrayBuffer', { loadStart: function (e) { // progressTextObj.innerText = "正在讀取文件(0%)..."; }, progress: function (e) { }, load: function (e, loaded, total) { // 如果在讀取的基礎(chǔ)上寫上傳的話在這里獲取讀取成功的文件切片 // e.target.result //當(dāng)前文件切片的數(shù)據(jù) socket.send(e.target.result); // 拿到進度,做進度條 obj.uploadSchedule = Math.round(loaded / total * 100); // if (obj.uploadSchedule < 100) { // // progressTextObj.innerText = '正在讀取文件(' + precent + '%)...'; // } else if (loaded >= total) { // progressTextObj.innerText = '文件讀取完成(100%)'; socket.send("end"); } }, loadend: function (e) { }, abort: function (e) { }, error: function (e) { // progressTextObj.innerText = "文件讀取出錯誤(~0v0~)"; } }) } // function sleep(time) { // return new Promise(function (resolve) { // setTimeout(resolve, time); // }); // } function openSocket(file,obj) { var socket if (typeof (WebSocket) == "undefined") { console.log("您的瀏覽器不支持WebSocket"); } else { console.log("您的瀏覽器支持WebSocket"); //實現(xiàn)化WebSocket對象,指定要連接的服務(wù)器地址與端口 建立連接 // var userId = document.getElementById('userId').value; var socketUrl = "ws://192.168.1.24:8081/webSocket/" + obj.userName; // var socketUrl = "ws://localhost:8081/webSocket/" + name; console.log(socketUrl); if (socket != null) { socket.close(); socket = null; } socket = new WebSocket(socketUrl); //打開事件 socket.onopen = function () { console.log("websocket已打開",obj); readFile(socket,file,obj) // WebSocket鏈接成功建立,可以在這里進行后端交互 //socket.send("這是來自客戶端的消息" + location.href + new Date()); }; //獲得消息事件 socket.onmessage = function (msg) { var serverMsg = "收到服務(wù)端信息:" + msg.data; console.log(serverMsg); //發(fā)現(xiàn)消息進入 開始處理前端觸發(fā)邏輯 }; //關(guān)閉事件 socket.onclose = function () { console.log("websocket已關(guān)閉"); }; //發(fā)生了錯誤事件 socket.onerror = function () { console.log("websocket發(fā)生了錯誤"); } } } function closeSocket(socket) {if (socket != null) { socket.close(); socket = null; } } export function uploadFilesW(file,obj){ openSocket(file,obj) }
頁面中使用
<template> <div> <input type="file" @change="fileChangeF($event,fileId)" /> </div> </template> <script> import { uploadFilesW } from "../../util/upfile" export default { data(){ return { expDialog:{ // 上傳文件彈窗 dialogVisible:false, cloudFile:null, // 云文件 trajectoryFile:null, // 云文件 explainFile:null, // 說明文件 uploadSchedule:0, // 上傳進度 precentState:'', // 文件上傳狀態(tài) 成功/失敗 showProgressBar:false, // 進度條展示 uploadBtncontent:1, isUpDisable: false, // 一個上傳完才可以上傳下一個 }, } }, methods:{ fileChangeF(eve,type){ // 上傳文件選擇文件 console.log(eve.target.files,type); let fi = eve.target.files let self = this let exp = self.expDialog uploadFilesW(fi[0],this.expDialog) console.log(exp); }, } } </script>
新增需求:對上傳文件流進行加密,并傳給后端做驗證
原文連接:使用React框架 http://www.dbjr.com.cn/article/264653.htm
實現(xiàn)方式: fileReader讀取文件并 使用md5加密文件
還是在同一個文件中,封裝了方法進行調(diào)用
安裝并引用spark-md5
需要先npm下載 spark-md5
npm i spark-md5 // 安裝spark-md5
還是在upfile.js文件(也可以單獨放一個文件)
import SparkMD5 from 'spark-md5'; function neverPromise(file) { return new Promise(resolve => { // 因為使用fileReader讀取文件是異步的,所以使用promise將加密之后的值返回方便傳給后端 let fileReader = new FileReader(), blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice, // chunkSize = 2097152, // read in chunks of 2MB chunkSize= 1024 * 1024 * 10,//1MB(單片大小/一兆) chunks = Math.ceil(file.size / chunkSize), currentChunk = 0, spark = new SparkMD5(), that = this, md5Str ; // console.log(Math.ceil(file.size / chunkSize),'file.size / chunkSize'); // console.log(chunks,'chunks'); fileReader.onload = function (e) { spark.appendBinary(e.target.result); // append binary string currentChunk++; if (currentChunk < chunks) { // 切片讀取完執(zhí)行 // 執(zhí)行這個方法才能短時間內(nèi)獲取到加密后的md5文件? loadNext(); } else { let md = spark.end(); // console.log(file,'file'); resolve(md.toUpperCase()) // 將數(shù)據(jù)返回 } }; function loadNext () { let start = currentChunk * chunkSize, end = start + chunkSize >= file.size ? file.size : start + chunkSize; console.log(blobSlice.call(file, start, end),'blobSlice.call(file, start, end)'); // readAsBinaryString這個函數(shù)看MDN上說是已經(jīng)棄用,readAsArrayBuffer來代替 // 但是后來發(fā)現(xiàn)這兩個函數(shù)讀取完文件加密后的值不同,為了跟后端同步使用了readAsBinaryString // fileReader.readAsBinaryString(blobSlice.call(file, start, end)); // fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); } loadNext(); }) } // 在使用的地方調(diào)用即可 let md5Send = await neverPromise(file)// 方法記得加async console.log(md5Send) // 就可以拿到讀取完并加密后的字符串
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue3中路由傳參query、params及動態(tài)路由傳參詳解
vue3中的傳參方式和vue2中一樣,都可以用query和params傳參,下面這篇文章主要給大家介紹了關(guān)于vue3中路由傳參query、params及動態(tài)路由傳參的相關(guān)資料,需要的朋友可以參考下2022-09-09VUE3自定義指令防止重復(fù)點擊多次提交的實現(xiàn)方法
vue3項目,新增彈框連續(xù)點擊確定按鈕防止多次提交,在按鈕上添加自定義指令,這篇文章主要介紹了VUE3自定義指令防止重復(fù)點擊多次提交的實現(xiàn)方法,需要的朋友可以參考下2024-08-08Vue.js實戰(zhàn)之組件之間的數(shù)據(jù)傳遞
這篇文章主要介紹了Vue.js實戰(zhàn)之組件之間的數(shù)據(jù)傳遞的相關(guān)資料,文中通過示例代碼和圖文介紹的非常詳細(xì),對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-04-04vue實現(xiàn)將圖像文件轉(zhuǎn)換為base64
這篇文章主要介紹了vue實現(xiàn)將圖像文件轉(zhuǎn)換為base64,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02