78

断点续传:顾名思义,继续上次断开的点,继续上传。

思路整理:

  1. 拿到文件,对文件进行fingerprint = md5(file),得到文件指纹。
  2. 将指纹保存服务器。
  3. 切割文件,分段上传,每次上传一段。
  4. 服务器根据指纹进行索引判断文件上传进度,直到文件的全部片段上传完毕。

以下文字没有完整的代码,只有基础理论,伸手党绕道。

1. 读取文件

// 这里只演示单文件上传过程。
var input = document.querySelector('input');
input.addEventListener('change', function() {
    var file = this.files[0];
    //这里是有一个坑的,部分设备(华为部分机型)无法获取文件名称,和文件类型,这个在最后给出解决方案
    var fileType = file.type;
    // getFileType(file, fileType => {})
});

2. 获取文件指纹

var fingerprint = md5(file);

3. 文件切割

var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.addEventListener("load", function(e) {
    //每10M切割一段,这里只做一个切割演示,实际切割需要根据file.size进行循环切割.
    let size = 1024 * 1024 * 10;
    var slice = e.target.result.slice(0, size);
});

4. h5上传一个(一片)文件

// 一般情况下不需要getFileType。
getFileType(file, fileType => {
    var formdata = new FormData();
    formdata.append('fingerprint', fingerprint);
    // 指纹作为文件名,并拼接文件类型(也可以在服务器断进行文件类型处理)
    formdata.append('filename', fingerprint + '.' + fileType);
    // 做好切片索引,把索引作为切片名称
    // 第一片为了保存指纹,可以尽量切小一点。
    formdata.append('0', slice);
    var xhr = new XMLHttpRequest();
    xhr.addEventListener('load', function () {
        //xhr.responseText
    });
    xhr.open('POST', '');
    xhr.send(formdata);
    xhr.addEventListener('progress', updateProgress);
    xhr.upload.addEventListener('progress', updateProgress);
});

function updateProgress(event) {
    if (event.lengthComputable) {
        //进度条
    }
}

无法获取文件类型的设备解决方案

首先在:http://www.garykessler.net/li...查找对应文件的头信息
这里只给出了常见的图片和视频的文件类型判断
function getFileType(file, back) {
    var name = file.name;
    var type = '';
    if (name) {
        var lastIndex = name.lastIndex('.')
        type = name.substring(lastIndex + 1)
        back(type);
        return;
    }
    // 如果系统无法获取文件类型,则读取二进制流,对二进制进行解析文件类型
    var imgType = {
        'ff d8 ff': 'jpg',
        '89 50 4e': 'png',

        '0 0 0 14 66 74 79 70 69 73 6F 6D': 'mp4',
        '0 0 0 18 66 74 79 70 33 67 70 35': 'mp4',
        '0 0 0 0 66 74 79 70 33 67 70 35': 'mp4',
        '0 0 0 0 66 74 79 70 4D 53 4E 56': 'mp4',
        '0 0 0 0 66 74 79 70 69 73 6F 6D': 'mp4',

        '0 0 0 18 66 74 79 70 6D 70 34 32': 'm4v',
        '0 0 0 0 66 74 79 70 6D 70 34 32': 'm4v',

        '0 0 0 14 66 74 79 70 71 74 20 20': 'mov',
        '0 0 0 0 66 74 79 70 71 74 20 20': 'mov',
        '0 0 0 0 6D 6F 6F 76': 'mov',

        '4F 67 67 53 0 02': 'ogg',
        '1A 45 DF A3': 'ogg',

        '52 49 46 46 x x x x 41 56 49 20': 'avi',
    }
    // 用最长的作为截取边界
    var size = Object.keys(imgType).map(i => i.split(/\s+/).length).sort()[0]
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.addEventListener("load", function (e) {
        var result = e.target.result
        if (!result || result.length < size) {
            back('')
            return;
        }
        var slice = result.slice(0, size);
        var view = new Uint8Array(slice);
        var arr = view.map(v => v.toString(16))

        type = imgType[arr.join(' ')];
        if (!type) {
            // 处理一个特殊情况:忽略第4-8位
            arr = arr.map(function (v) {
                if (i > 3 && i < 8) {
                    return 'x';
                }
                return v;
            });
            type = imgType[arr.join(' ')];
        }

        back(type);
    });
}

总结:有了切割上传,有了文件唯一标识信息(文件md5)断点续传只不过是后台的一个小小的判断逻辑而已。

未来,前端,大有可为


有些小伙伴不是太清楚后台的小小的判断是怎么做的:
这里贴一张图给大家参考,自己手画,有点丑,将就下。

clipboard.png


jsoncode
4k 声望786 粉丝

I'm jsoncode