如何在不溢出 RAM 的情况下为非常大的文件生成校验和并在 Javascript 中转换为 64 位?
How to generate checksum & convert to 64 bit in Javascript for very large files without overflowing RAM?
问题:
如何正确生成独立于浏览器的唯一、一致的校验和?另外,我想将 SHA256/MD5 校验和字符串转换为 64 位。
如何在不需要大量 RAM 的情况下正确读取文件来生成校验和?即我们如何在不影响 RAM
的情况下处理 1 GB 的文件
例如(见答案)
This project 看起来很有希望,但也无法实现。
我的意图是以 X MB 的块生成校验和 progressively/incrementally。这可能有助于避免一次使用过多的 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();
}
在不同的浏览器中显示不同的结果。
下一行代码中存在逻辑问题:
start = chunkCount * SIZE_CHECKSUM; // <--- bug
变量start
初始化为0,然后在第1次迭代中再次重置为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();
}
以上代码在我的所有浏览器中为任何块大小生成相同的校验和。
问题:
如何正确生成独立于浏览器的唯一、一致的校验和?另外,我想将 SHA256/MD5 校验和字符串转换为 64 位。
如何在不需要大量 RAM 的情况下正确读取文件来生成校验和?即我们如何在不影响 RAM
的情况下处理 1 GB 的文件
例如
This project 看起来很有希望,但也无法实现。
我的意图是以 X MB 的块生成校验和 progressively/incrementally。这可能有助于避免一次使用过多的 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();
}
在不同的浏览器中显示不同的结果。
下一行代码中存在逻辑问题:
start = chunkCount * SIZE_CHECKSUM; // <--- bug
变量start
初始化为0,然后在第1次迭代中再次重置为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();
}
以上代码在我的所有浏览器中为任何块大小生成相同的校验和。