【前端文件计算】浏览器计算大文件SHA256——网页崩溃问题解决

时间:2021-1-8 作者:admin

前言

最近公司在做文件存证的功能:文件存证上传之后得到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)描述的是内存中的一段二进制数据,缓冲没有格式可言,并且不提供机制访问其内容。为了访问在缓存对象中包含的内存,你需要使用视图。视图可以将二进制数据转换为实际有类型的数组。一个缓冲可以提供给多个视图进行读取,不同类型的视图读取的内存长度不同,读取出来的数据格式也不同。缓冲和视图的工作方式如下图所示:
![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8610bbabd5b84996ac32c70ccd3587f6~tplv-k3u1fbpfcp-watermark.image)

我们常见的各种编码、散列、加密算法,其基础都是位操作。

不管是对哪种数据类型,位操作对象的本质都是一段连续的比特序列。从性能的角度讲,位操作最好是能直接操作连续的内存位。那就是通过二进制位操作符。在含有位操作符的运算中,都得通过 ToInt32() 转换为 32 位有符号整数,然后将其当做 32 位的比特序列进行位运算,运算结果返回也为 32 位有符号整数。因此,通过拼接 32 位有符号整数,就可以实现“对一段连续的比特序列进行位操作”的功能了。

正是基于这样的原理, CryptoJs 实现了名为WordArray的类,作为“一段连续比特序列”的抽象进行各种位操作。 WordArrayCryptoJs 中最核心的一个类,所有主要算法的实际操作对象都是WordArray对象。理解WordArray是理解CryptoJs各算法的基础
words 为 32 位有符号整数构成的数组,通过按顺序拼接数组中的数,就组成了比特序列。 JavaScript 中 32 位有符号整数是通过补码转换为二进制的,不过在这里我们不需要关注这点,因为这个整数的值是没有意义的,实际使用中,比特序列更多的是用字节作单位,或用 16 进制数表示,因此我们只需要知道 32 位等价于 4 个字节,等价 于 8个 16 进制数。

问题出现

1、读取的文件大小一旦超过1GB左右就会长时间页面没有反应或者直接读取500MB左右并去计算会直接导致内存溢出页面崩溃,因为初始阶段的计算是用CryptoJS.lib.WordArray.create,这个方法短时间内会不断的开辟新的内存来保存二进制数组得不到释放。原因可以看看浏览器垃圾回收专栏

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。