前言
最近公司在做文件存证的功能:文件存证上传之后得到SHA256值,当区块链or法庭需要用到的时候,比较SHA值,若文件被改动,SHA256值都会产生变化。因此前端需要对文件进行读取并用文件数据计算出SHA256值,需要用到文件读取类
new FileReader()
,并用散列算法SHA256
进行计算,但是一旦计算大文件就会出现网页假死/崩溃情况,切片也不能解决因为问题出在了计算上面,需要用到new Works()
为 JavaScript 创造多线程环境,当然高版本的浏览器有内置计算函数,速度更快但兼容性没有new Works()好。下面就讲解一下问题的出现/解决思路,仅供参考!
这种问题记录文很少写,有什么不对的地方,错误的思维,欢迎大家指出,纠正。感谢大家了
初始阶段的文件读取
Vue演示:
input获取文件的的Blob值,前期为了节省时间是用crypto-js
中的SHA256()进行计算。记得npm install crypto-js –save,后面拆解算法就不需要这个包了
<input type="file" @change="inputChange" />
import CryptoJS from 'crypto-js' //... methods:{ inputChange(e){ let files = e.target.files[0]; //生成实例 let fileReads = new FileReader(); //开始读取文件 fileReads.readAsArrayBuffer(files); //读取回调 fileReads.onload=function(){ console.log('读取结果(文件数据类型:ArrayBuffer):',fileReads.result) var wordArray = CryptoJS.lib.WordArray.create(fileReads.result); console.log('ArrayBuffer转为WordArray格式:',wordArray) var hash = CryptoJS.SHA256(wordArray).toString(); console.log('SHA256:',hash) } }
Blob 对象表示一个不可变、原始数据的类文件对象。
小课堂
来源:JavaScript类型化数组(二进制数组)
`ECMAScript 6` 中的 `ArrayBuffer`是类型化数组,也就是读取文件得到的缓冲内存,需要转换一下格式才能被计算
类型化数组的诞生就是为了能够让开发者通过类型化数组来操作内存,大大增强了JavaScript处理二进制数据的能力。
JavaScript类型化数组将实现拆分为缓冲和视图两部分。一个缓冲(ArrayBuffer)描述的是内存中的一段二进制数据,缓冲没有格式可言,并且不提供机制访问其内容。为了访问在缓存对象中包含的内存,你需要使用视图。视图可以将二进制数据转换为实际有类型的数组。一个缓冲可以提供给多个视图进行读取,不同类型的视图读取的内存长度不同,读取出来的数据格式也不同。缓冲和视图的工作方式如下图所示:

我们常见的各种编码、散列、加密算法,其基础都是位操作。
不管是对哪种数据类型,位操作对象的本质都是一段连续的比特序列。从性能的角度讲,位操作最好是能直接操作连续的内存位。那就是通过二进制位操作符。在含有位操作符的运算中,都得通过 ToInt32()
转换为 32 位有符号整数,然后将其当做 32 位的比特序列进行位运算,运算结果返回也为 32 位有符号整数。因此,通过拼接 32 位有符号整数,就可以实现“对一段连续的比特序列进行位操作”的功能了。
正是基于这样的原理, CryptoJs
实现了名为WordArray
的类,作为“一段连续比特序列”的抽象进行各种位操作。 WordArray
是 CryptoJs
中最核心的一个类,所有主要算法的实际操作对象都是WordArray
对象。理解WordArray
是理解CryptoJs
各算法的基础
words 为 32 位有符号整数构成的数组,通过按顺序拼接数组中的数,就组成了比特序列。 JavaScript 中 32 位有符号整数是通过补码转换为二进制的,不过在这里我们不需要关注这点,因为这个整数的值是没有意义的,实际使用中,比特序列更多的是用字节作单位,或用 16 进制数表示,因此我们只需要知道 32 位等价于 4 个字节,等价 于 8个 16 进制数。
问题出现
1、读取的文件大小一旦超过1GB左右就会长时间页面没有反应或者直接读取500MB左右并去计算会直接导致内存溢出页面崩溃,因为初始阶段的计算是用CryptoJS.lib.WordArray.create,这个方法短时间内会不断的开辟新的内存来保存二进制数组得不到释放。原因可以看看浏览器垃圾回收专栏。