一篇纯代码的文章。更多的说明在代码中
<template>
<div>
<input type="file" @change="calculate" />
</div>
</template>
<script>
import CryptoJs from 'crypto-js'
import encHex from 'crypto-js/enc-hex'
/**
* 用于计算文件的hash值,包括sha256值和md5值
*/
function hashFile (file) {
/**
* 使用指定的算法计算hash值
*/
function hashFileInternal (file, alog) {
// 指定块的大小,这里设置为20MB,可以根据实际情况进行配置
const chunkSize = 20 * 1024 * 1024
let promise = Promise.resolve()
// 使用promise来串联hash计算的顺序。因为FileReader是在事件中处理文件内容的,必须要通过某种机制来保证update的顺序是文件正确的顺序
for (let index = 0; index < file.size; index += chunkSize) {
promise = promise.then(() => hashBlob(file.slice(index, index + chunkSize)))
}
/**
* 更新文件块的hash值
*/
function hashBlob (blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = ({ target }) => {
const wordArray = CryptoJs.lib.WordArray.create(target.result)
// 增量更新计算结果
alog.update(wordArray)
resolve()
}
reader.readAsArrayBuffer(blob)
})
}
// 使用promise返回最终的计算结果
return promise.then(() => encHex.stringify(alog.finalize()))
}
// 同时计算文件的sha256和md5,并使用promise返回
return Promise.all([hashFileInternal(file, CryptoJs.algo.SHA256.create()),
hashFileInternal(file, CryptoJs.algo.MD5.create())])
.then(([sha256, md5]) => ({
sha256,
md5
}))
}
export default {
methods: {
calculate ({ target: { files } }) {
for (const file of files) {
hashFile(file).then(console.log)
}
}
}
}
</script>
代码是一个vue组件,但没有用到特殊的vue方法,仅仅是调试的时候用了它而已。代码理论上可以用于任何框架。
代码的核心是crypto-js库的使用。
通过对文件进行切片和增量更新hash的方式对文件进行hash计算,可以避免浏览器out of memory错误
使用异步计算hash值,计算返回promise,在promise.then()中获取计算结果