一直以來我都特別好奇,網上很多文件斷點上傳是怎么實現的,像百度雲,最近看到一篇關於HTML5新特性的文章,里面的BLOB對象和FILE對象,有一個slice方法,可以將BLOB對象進行分割。BLOB(Binary Large Object)二進制大對象,屬於XMLHttpRequest2.0中的一員,它的slice方法和字符串和數組的slice方法一樣,用於分割二進制。
文件上傳后台我是使用php的,上傳的策略是先請求后台詢問上傳的文件是否存在,如果存在則發回已經上傳到哪里。然后前端拿到這個位置,對文件二進制進行分割。
好,先看看我前端的實現,后台寫得太爛,我就不貼出來了,php的文件主要使用兩個函數,一個是file_put_contents,還有就是file_get_contents
<!DOCTYPE html> <html> <head> <title>斷點續傳</title> </head> <style type="text/css"> input[type="file" i] { width: 100px; height: 50px; opacity: 0; /*visibility: hidden;*/ margin: 0; padding: 0; border: 0; float: left; } .upload-button-wrap { position: relative; display: inline-block; vertical-align: middle; } .upload-button-wrap:hover .upload-button { border-color: #000; } .clearfix:after { content: ''; clear: both; display: block; } .clearfix { zoom: 1; } .upload-button { width: 100px; height: 50px; position: absolute; left: 0; top: 0; z-index: -1; } .upload-wrap { position: relative; } #uploadButton { display: inline-block; } </style> <body> <div class="upload-wrap"> <div class="upload-button-wrap clearfix"> <input type="file" id="uploadFile"> <button class="upload-button">選擇圖片</button> </div> <button id="uploadButton">上傳</button> </div> <script type="text/javascript"> (function (w) { var fileUpload = function (config) { var _files = [], // 要上傳文件的隊列 _file = null, // 當前上傳的文件 _upload = config.uploadId, // input[type = "file"]的控件ID _submit = config.submitId, // input[type = "submit"]的控件ID _url = config.url, _unit = 1024, _start = 0, _xmlRequest = new XMLHttpRequest(); var _init = function () { document.getElementById(_upload).addEventListener("change", function (e) { _files = this.files; _file = _files[0]; e.preventDefault(); }, false); document.getElementById(_submit).addEventListener("click", function (e) { // 向后抬請求文件是否存在 _xmlRequest.onload = function () { if (_xmlRequest.readyState == 4 && _xmlRequest.status == 200) { _start = parseInt(_xmlRequest.responseText); _uploadFile(); } _xmlRequest.onload = function () { if (_xmlRequest.readyState == 4 && _xmlRequest.status == 200) { if (_xmlRequest.responseText == "success") { _start = _start + _unit; _uploadFile(); } } } }; _getSetbacks(); e.preventDefault(); }, false); }, // 獲取文件進度 _getSetbacks = function () { _xmlRequest.open("GET", _url+"?fileName="+_file.name, true); _xmlRequest.send(null); }, // 上傳文件 _uploadFile = function () { if (_start > _file.size) return; console.log(_start); var formData = new FormData(); formData.append('fileName', _file.name); formData.append('fileContent', _file.slice(_start,_start+_unit)); _xmlRequest.open("POST", _url, true); _xmlRequest.send(formData); }; _init() } w.fileUpload = fileUpload; })(window) var f = new fileUpload({ uploadId: 'uploadFile', submitId: 'uploadButton', url: './upload.php' }) </script> </body> </html>
我先請求后台,通過_getSetback函數獲取文件進度,返回的是已經上傳文件的大小,然后根據文件大小對文件進行切分(slice),最后通過_uploadFile分多次上傳文件。