代码之家  ›  专栏  ›  技术社区  ›  iammilind

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

  •  7
  • iammilind  · 技术社区  · 8 年前

    :

    1. 如何正确地读取一个文件而不需要大量的RAM来生成校验和?i、 e.如何在不影响RAM的情况下处理1GB文件

    例如 Is it possible to read a file without loading it into memory? (见答案)

    This project 看起来很有希望,但也没能成功。


    我的目的是以X MBs为单位逐步/递增地生成校验和。这可能有助于避免一次使用过多的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();
    }
    

    1 回复  |  直到 8 年前
        1
  •  2
  •   iammilind    8 年前

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

    start = chunkCount * SIZE_CHECKSUM;  // <--- bug
    

    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;
    }
    

    然后按如下方式使用:

    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();
    }