项目需要上传超大文件,后台为DJANGO,不能直接用H5 的FILE API来POST,所以采用slice分片
在分片后为BLOB不能直接传,bolb转file有些浏览器又有支持问题。所以做一些转换,转uint8,uint16,uint32,django的后台处理起来都比较烦
所以试着用base64装入json,很容易搞定。
具体思路:
1.读入文件路径
2.按固定size分片
3.给每个片段加入id,blob的内容提取成base64,json封装
4.js同步post,或者Ajax 异步post json到后台(使用队列防止浏览器卡住),
5.后台收到后拼装(注意文件锁和顺序)
前端代码
<!DOCTYPE html> <head> <title>yyb</title> <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.1.min.js"></script> </head> <style> #byte_content { margin: 5px 0; max-height: 100px; overflow-y: auto; overflow-x: hidden; } #byte_range { margin-top: 5px; } </style> <input type="file" id="files" name="file" /> Read bytes: <span class="readBytesButtons"> <button>send file</button> </span> <div id="byte_range"></div> <div id="byte_content"></div> <script> function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } </script> <script> function readBlob(opt_startByte, opt_stopByte,index) { var files = document.getElementById('files').files; if (!files.length) { alert('Please select a file!'); return; } var file = files[0]; var start = parseInt(opt_startByte) || 0; var stop = parseInt(opt_stopByte) || file.size - 1; var reader = new FileReader(); reader.onloadend = function(evt) { if (evt.target.readyState == FileReader.DONE) { // DONE == 2 document.getElementById('byte_range').textContent = ['send bytes: ', start, ' - ', stop, ' of ', file.size, ' byte file'].join(''); //----------json data var block_size=opt_stopByte-opt_startByte; var base64String = btoa(String.fromCharCode.apply(null,new Uint8Array(reader.result))); //base64 with no gzip if you want to improve you can use gzip compress base64 var send_data={'filename':file.name,'id':index,'blobdata':base64String,'filesize':file.size,'block':block_size}; //-------------ajax start console.log(send_data); function sync_send(URL, PARAMS) { var temp = document.createElement("form"); temp.action = URL; temp.method = "post"; temp.style.display = "none"; for (var x in PARAMS) { var opt = document.createElement("textarea"); opt.name = x; opt.value = PARAMS[x]; temp.appendChild(opt); } document.body.appendChild(temp); temp.submit(); return temp; } function async_send() { $.ajax({ url: '/upload/', type: 'post', data: send_data, tradition:true, success: function (data) { console.log("upload succeed"); if(opt_stopByte<file.size){ readBlob(opt_startByte+block_size,opt_stopByte+block_size,index+1) } }, beforeSend: function (xhr, settings) {//set csrf cookie var csrftoken = getCookie('csrftoken'); if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } }, error: function (jqXHR, textStatus, errorThrown) { alert(textStatus + " : " + errorThrown); } }); //---------ajax end } async_send('/upload/',send_data); } }; if(window.File && window.FileList && window.FileReader && window.Blob) { } else { alert('您的浏览器不支持File Api'); } if(stop>file.size){ stop=file.size; } var blob=file.slice(start,stop); reader.readAsArrayBuffer(blob); } document.querySelector('.readBytesButtons').addEventListener('click', function(evt) { if (evt.target.tagName.toLowerCase() == 'button') { var o_files = (document.getElementById('files').files); var o_file=o_files[0]; var block=1024*100; console.log(o_file.size); readBlob(0, 0+block,0); } }, false); </script>