项目需要上传超大文件,后台为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>
参考文章:http://blog.ncmem.com/wordpress/2023/10/22/基于js的大文件分片/