import sha1JS from 'js-sha1'; export const getEtag = (buffer) => { return new Promise((resolve, reject) => { // sha1算法 const sha1 = sha1JS.digest; // 以4M为单位分割 const blockSize = 4 * 1024 * 1024; const sha1String = [] as any[]; let prefix = 0x16; let blockCount = 0; const fileReader = new FileReader(); fileReader.onerror = (e) => { reject(e); }; const concatArr2Uint8 = (s) => { // Array 2 Uint8Array let tmp = []; s.forEach((e) => { tmp = tmp.concat(e); }); return new Uint8Array(tmp); }; const Uint8ToBase64 = (u8Arr, urisafe) => { // Uint8Array 2 Base64 const CHUNK_SIZE = 0x8000; // arbitrary number let index = 0; const { length } = u8Arr; let result = ''; let slice; while (index < length) { slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length)); result += String.fromCharCode.apply(null, slice); index += CHUNK_SIZE; } return urisafe ? btoa(result).replace(/\//g, '_').replace(/\+/g, '-') : btoa(result); }; const calcEtag = () => { if (!sha1String.length) { return ''; } let sha1Buffer = concatArr2Uint8(sha1String); let sha1Array = [] as number[]; // 如果大于4M,则对各个块的sha1结果再次sha1 if (blockCount > 1) { prefix = 0x96; sha1Array = sha1(sha1Buffer.buffer); } else { sha1Array = Array.from(sha1Buffer); } sha1Buffer = concatArr2Uint8([[prefix], sha1Array]); return Uint8ToBase64(sha1Buffer, true); }; const processBlock = (block_start: number) => { const block_end = Math.min(buffer.size, block_start + blockSize); fileReader.readAsArrayBuffer(buffer.slice(block_start, block_end)); }; fileReader.onload = (e: any) => { sha1String.push(sha1(e.target.result)); blockCount += 1; if (blockCount * blockSize < buffer.size) { processBlock(blockCount * blockSize); } else { resolve(calcEtag()); } }; processBlock(0); }); };