TypeScript 代码详解:大文件 MD5 异步计算

  return new Promise<string>((resolve, reject) => {
    const chunkSize = 1024 * 1024; // 1MB
    const spark = new SparkMd5.ArrayBuffer();
    const fileReader = new FileReader();
    let cursor = 0;

    fileReader.onload = function (e: any) {
      spark.append(e.target.result);
      cursor += chunkSize;
      if (cursor < file.size) {
        processNextChunk();
      } else {
        resolve(spark.end()); // 返回MD5哈希值
      }
    };

    fileReader.onerror = function () {
      reject(new Error("文件读取错误"));
    };

    function processNextChunk() {
      const chunk = file.slice(cursor, cursor + chunkSize);
      fileReader.readAsArrayBuffer(chunk);
    }

    processNextChunk();
  });
}

这段代码的核心作用是异步计算一个文件的 MD5 哈希值,并且采用了分片读取的方式来处理大文件,避免一次性读取整个文件导致内存占用过高。

代码整体功能与逐行解释

首先,先总结这段代码的核心功能:这是一个异步函数 calculateMd5,接收一个 File 对象作为参数,通过分片读取文件内容并逐步计算,最终返回该文件的 MD5 哈希值字符串。这种分片处理的方式特别适合大文件,能有效控制内存使用。

下面是逐行/逐块的详细解释:


async calculateMd5(file: File): Promise<string> {
  • 定义一个异步函数 calculateMd5,参数 file 是浏览器的 File 对象(通常来自文件上传控件),函数返回一个 Promise,最终会解析为 MD5 哈希值的字符串。

  • async 关键字标记这是异步函数,函数内部可以使用 await,但这里函数体直接返回了一个新的 Promise,是异步处理的另一种写法。


  return new Promise<string>((resolve, reject) => {
  • 函数返回一个新的 Promise 实例,泛型 <string> 表示这个 Promise 最终会返回字符串类型的结果。

  • resolve 是 Promise 成功时的回调,用于返回最终的 MD5 值;reject 是失败时的回调,用于抛出错误。


    const chunkSize = 1024 * 1024; // 1MB
  • 定义分片大小为 1MB(1024*1024 字节),表示每次只读取文件的 1MB 内容,避免一次性读取大文件导致内存溢出。

    const spark = new SparkMd5.ArrayBuffer();
  • 实例化 SparkMd5ArrayBuffer 版本(SparkMd5 是一个轻量的 MD5 计算库,运行在浏览器端,支持分片计算)。

  • ArrayBuffer 版本适配 FileReader 读取的 ArrayBuffer 格式数据,是处理二进制文件的最优选择。


    const fileReader = new FileReader();
    let cursor = 0;
  • fileReader:浏览器内置的 FileReader 对象,用于读取文件的二进制内容。

  • cursor(游标):记录当前读取到文件的哪个位置,初始值为 0(从文件开头开始读取)。


    fileReader.onload = function (e: any) {
      spark.append(e.target.result);
      cursor += chunkSize;
      if (cursor < file.size) {
        processNextChunk();
      } else {
        resolve(spark.end()); // 返回MD5哈希值
      }
    };
  • fileReader.onloadFileReader 读取完一块内容后的回调函数(异步触发)。

    1. spark.append(e.target.result):将当前读取到的文件分片(ArrayBuffer 格式)追加到 SparkMd5 实例中,逐步累积计算 MD5。

    2. cursor += chunkSize:游标后移,指向下一个分片的起始位置。

    3. if (cursor < file.size):判断是否还有未读取的文件内容:

      • 有:调用 processNextChunk() 读取下一个分片。

      • 无:调用 spark.end() 完成 MD5 计算,并通过 resolve 返回最终的哈希字符串。


    fileReader.onerror = function () {
      reject(new Error("文件读取错误"));
    };
  • fileReader.onerrorFileReader 读取文件出错时的回调,通过 reject 抛出“文件读取错误”的异常,让调用方可以捕获错误。

    function processNextChunk() {
      const chunk = file.slice(cursor, cursor + chunkSize);
      fileReader.readAsArrayBuffer(chunk);
    }
  • 定义 processNextChunk 函数,负责读取下一个文件分片:

    1. file.slice(cursor, cursor + chunkSize):从文件的 cursor 位置开始,截取到 cursor + chunkSize 位置的分片(最后一个分片可能小于 1MB)。

    2. fileReader.readAsArrayBuffer(chunk):将截取的分片以 ArrayBuffer 格式读取(二进制格式),读取完成后会触发 onload 回调。


    processNextChunk();
  });
}
  • 调用 processNextChunk() 启动第一个分片的读取,开始整个 MD5 计算流程。

代码执行流程(可视化)

调用calculateMd5传入File

初始化分片大小、SparkMd5、FileReader、游标

调用processNextChunk读取第一个分片

FileReader读取分片为ArrayBuffer

读取成功?

SparkMd5追加分片内容,游标后移

游标<文件大小?

计算完成,resolve返回MD5

reject抛出文件读取错误

前置条件

要让这段代码正常运行,你需要:

  1. 在项目中引入 spark-md5 库(浏览器端 MD5 计算库):

    
    # npm 安装
    npm install spark-md5
    # 或 yarn
    yarn add spark-md5
    
  2. 代码运行环境是浏览器(因为用到了 FileReaderFile 等浏览器专属 API,Node.js 环境不适用)。

调用示例


// 假设你有一个文件上传的 input 元素
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fileInput.addEventListener('change', async (e) => {
  const file = fileInput.files?.[0];
  if (file) {
    try {
      const md5 = await calculateMd5(file);
      console.log('文件MD5:', md5);
    } catch (error) {
      console.error('计算MD5失败:', error);
    }
  }
});

总结

  1. 核心逻辑:通过分片读取文件 + SparkMd5 逐步追加计算,实现大文件 MD5 异步计算,避免内存溢出。

  2. 关键API:FileReader.readAsArrayBuffer(读取二进制分片)、SparkMd5.ArrayBuffer.append/end(分片计算MD5)、File.slice(截取文件分片)。

  3. 异常处理:捕获 FileReader 读取错误,通过 Promise 的 reject 抛出,保证代码健壮性。

(注:文档部分内容可能由 AI 生成)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐