如何生成校验和并在Javascript中转换为64位非常大的文件而不会溢出RAM?

iam*_*ind 7 javascript algorithm checksum sha256 typescript

问题:

  1. 如何正确生成校验和,这是独立的,一致的,独立于浏览器?另外,我想将SHA256/MD5校验和字符串转换为64位.

  2. 如何在没有大量RAM要求的情况下正确读取文件以生成校验和?即我们如何在不影响RAM的情况下处理1 GB文件

例如,是否可以在不将文件加载到内存的情况下读取文件?(见答案)

这个项目似乎很有希望,但也无法实现.


我的目的是在X MB的块中逐步/递增地生成校验和.这可能有助于避免一次使用太多RAM.
以下是代码,它没有按预期工作:

let SIZE_CHECKSUM = 10 * Math.pow(1024, 2); // 10 MB; But can be 1 MB too
async function GetChecksum (file: File):
Promise<string>
{
  let hashAlgorithm: CryptoJS.lib.IHasher<Object> = CryptoJS.algo.SHA256.create();
  let totalChunks: number = Math.ceil(file.size / SIZE_CHECKSUM);
  for (let chunkCount = 0, start = 0, end = 0; chunkCount < totalChunks; ++chunkCount)
  {
    end = Math.min(start + SIZE_CHECKSUM, file.size);
    let resultChunk: string = await (new Response(file.slice(start, end)).text());
    hashAlgorithm.update(resultChunk);
    start = chunkCount * SIZE_CHECKSUM;
  }
  let long: bigInt.BigInteger = bigInt.fromArray(hashAlgorithm.finalize().words, 16, false);
  if(long.compareTo(bigInt.zero) < 0)
    long = long.add(bigInt.one.shiftLeft(64));
  return long.toString();
}
Run Code Online (Sandbox Code Playgroud)

它在不同的浏览器中显示不同的结果

Swa*_*nil 2

下面一行代码存在逻辑问题:

start = chunkCount * SIZE_CHECKSUM;  // <--- bug
Run Code Online (Sandbox Code Playgroud)

该变量start被初始化为 0,然后在第一次迭代中再次重置为 0,这是不对的。
以下是使用问题中提到的相同库获取 32 字节 SHA5 校验和的方法:“ emn178/js-sha256 ”。

该库不提供 Typescript 接口,但我们可以简单地定义如下:

// Sha256.d.ts  (also name the corresponding JS file as "Sha256.js")
declare class Sha256 {
  update (data: ArrayBuffer): Sha256;
  hex (): string;
}

declare var sha256: any;
declare interface sha256 {
  create (): Sha256;
}
Run Code Online (Sandbox Code Playgroud)

然后按如下方式使用它:

import "./external/Sha256"

async function GetChecksum (file: File):
Promise<string>
{
  let algorithm = sha256.create(); 
  for(let chunkCount = 0, totalChunks = Math.ceil(file.size / SIZE_CHECKSUM); 
      chunkCount < totalChunks;
      ++chunkCount)
  {
    let start = chunkCount * SIZE_CHECKSUM, end = Math.min(start + SIZE_CHECKSUM, file.size); 
    algorithm.update(await (new Response(file.slice(start, end)).arrayBuffer()));
  }
  return algorithm.hex();
}
Run Code Online (Sandbox Code Playgroud)

上面的代码在我的所有浏览器中针对任何块大小生成相同的校验和。