实现文件去重和大文件上传

652 阅读3分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

背景

假如我们现在有一个很大的图片(>20M)要上传到服务器,怎么办?通过FormData,单线上传? 这样上传简单的文件没有问题!但是图片大了,网络满了怎么了办?

答案:文件切片上传,断点上传。

技术

spark-md5

github: github.com/satazor/js-…

npmjs : www.npmjs.com/package/spa…

实现

安装

npm install --save spark-md5

安装好后你的package.json文件中就会多出"spark-md5": "^3.0.0",

image.png

计算文件MD5

为什么要计算MD5?

答:因为对于一个文件他的MD5是固定的,如果你不改变文件的内容,MD5是不会变的,这样就可以传值给后端比较文件的准确性和完整性、一致性、不重复。

通过MD5我们可以实现文件的去重

  1. 一般文件(小于2M)

一种是用SparkMD5.hashBinary() 直接将整个文件的二进制码传入,直接返回文件的md5。

  1. 体积较大的文件 一般我们做上传的时候推荐使用分片的方式,因为文件的体积不确定,这种方式对于大体积的文件计算更加稳定,还可以获得计算进度的信息。

计算代码如下:

import SparkMD5 from 'spark-md5'
let getMD5 = function (request, callback) {
  let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
  let chunkSize = 2097152 // 每次读取2MB
  let file = request.file
  let chunks = Math.ceil(file.size / chunkSize)
  let currentChunk = 0
  let spark = new SparkMD5.ArrayBuffer()
  let fileReader = new FileReader()

  fileReader.onload = function (e) {
    console.info('array buffer', e) // Compute hash
    spark.append(e.target.result) // Append array buffer
    currentChunk++

    if (currentChunk < chunks) {
      loadNext()
    } else {
      console.log('finished loading')
      console.info('computed hash', spark.end()) // Compute hash
      callback(request, spark.end())
    }
  }
  fileReader.onerror = function () {
    console.warn('oops, something went wrong.')
  }
  function loadNext () {
    let start = currentChunk * chunkSize
    let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize

    fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
  }
  loadNext()
}
export default {getMD5}

生成切片

//把文件切片,生成文件块 
createFileChunks(file) { 
    const chunkSize = 2 * 1024 * 1024;// 把文件分块指定成2M大小 
    const chunks = []; 
    let curSize = 0; 
    
    while(cur < file.size) { 
        chunks.push({ 
            index: chunks.length, file: file.slice(curSize, curSize + chunkSize) 
        }); 
        curSize += size; 
     } 
     return chunks; 
 }

SparkMD5方法

append(str)

添加一个字符串。

appendBinary(str)

添加一个二进制字符串。

end()

完成 md5 的计算,返回 hex 结果。如果raw为真,则将返回二进制字符串的结果。

reset()

重置计算的内部状态。

getState()

返回一个表示内部计算状态的对象。您可以将此状态传递给 setState()。此功能对于恢复增量 md5 很有用。

setState(state)

设置内部计算状态。

destroy()

释放增量缓冲区和其他附加资源使用的内存。

hash(str, raw)

直接散列一个字符串,返回十六进制结果。如果rawtrue,则将返回二进制字符串的结果。注意这个函数是static

hashBinary(str, raw)

直接散列二进制字符串,返回十六进制结果。如果rawtrue,则将返回二进制字符串的结果。注意这个函数是static

SparkMD5.ArrayBuffer方法

append(arr)

添加一个数组缓冲区。

end(raw)

完成 md5 的计算,返回 hex 结果。如果rawtrue,则将返回二进制字符串的结果。

reset()

重置计算的内部状态。

destroy()

释放增量缓冲区和其他附加资源使用的内存。

getState()

返回一个表示内部计算状态的对象。您可以将此状态传递给 setState()。此功能对于恢复增量 md5 很有用。

setState(state)

设置内部计算状态。

hash(arr, raw)

直接散列数组缓冲区,返回十六进制结果。如果rawtrue,则将返回二进制字符串的结果。注意这个函数是static.

往期文章