Bootstrap

基于JS的大文件分片

项目需要上传超大文件,后台为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>

 

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;