//计算文件的hash
fileHash(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
this.hash = sha1.create();
let thit = this;
reader.onload = ({ target }) => {
console.log(target.result);
thit.hash.update(target.result); //thit.hash.toString() 就是文件hash
var array = new Uint8Array(target.result);
var fileByteArray = [];
for (let i = 0; i < array.length; i++) {
fileByteArray.push(array[i]);
}
console.log(fileByteArray); //fileByteArray是文件的二进制数组
thit.chunkBody = fileByteArray;
resolve();
};
reader.readAsArrayBuffer(blob);
});
},
问题是,提交接口的时候,后台说我hash和文件流不匹配
拿到原文件的 hash
值是关键的一步,同一个文件就算改文件名,hash
值也不会变,就可以避免文件改名后重复上传的问题。
这里,我们使用 spark-md5.min.js 来根据文件的二进制内容计算文件的 hash
。
说明:考虑到如果上传一个超大文件,读取文件内容计算 hash 是非常耗费时间的,并且会引起 UI 的阻塞,导致页面假死状态,所以我们使用 web-worker 在 worker 线程计算 hash,这样用户仍可以在主界面正常的交互。
由于实例化 web-worker 时,参数是一个 js 文件路径且不能跨域,所以我们单独创建一个 hash.js 文件放在 public 目录下,另外在 worker 中也是不允许访问 dom 的,但它提供了importScripts 函数用于导入外部脚本,通过它导入 spark-md5。
计算 hash
代码如下:
// public/hash.js
self.onmessage = e => {
const { fileChunkList } = e.data
const spark = new self.SparkMD5.ArrayBuffer()
let percentage = 0
let count = 0
const loadNext = index => {
const reader = new FileReader()
reader.readAsArrayBuffer(fileChunkList[index].file)
reader.onload = e => {
count++
spark.append(e.target.result)
if (count === fileChunkList.length) {
self.postMessage({
percentage: 100,
hash: spark.end()
})
self.close()
} else {
percentage += 100 / fileChunkList.length
self.postMessage({
percentage
})
loadNext(count)
}
}
}
loadNext(count)
}
我们传入切片后的 fileChunkList
,利用 FileReader
读取每个切片的 ArrayBuffer
并不断传入 spark-md5
中,每计算完一个切片通过 postMessage
向主线程发送一个进度事件,全部完成后将最终的 hash
发送给主线程。
【重要说明】
spark-md5
需要根据所有切片才能算出一个hash
值,不能直接将整个文件放入计算,否则即使不同文件也会有相同的hash
,具体可以看官方文档 spark-md5。
根据和后台的沟通,他说的是我传的二进制数据流和他收到的不一样导致文件传输失败,但是我传递的文件有的能成功,有的不能。我实在是找不到问题在哪,他说他测试的是没问题的