You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Crypto.js计算大文件MD5时遇Invalid array length错误的解决咨询

问题:大文件MD5加密触发"Invalid array length"错误

实现文件上传功能时,使用Crypto.js对文件做MD5加密,当文件超过200Mb时,抛出Uncaught RangeError: Invalid array length错误,代码如下:

<script>
import CryptoJS from 'crypto-js'
const calculateMD5 = (file) => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader()
    fileReader.onload = function () {
      const hash = CryptoJS.MD5(CryptoJS.lib.WordArray.create(fileReader.result))
      resolve(hash.toString())
    }
    fileReader.onerror = reject
    fileReader.readAsArrayBuffer(file)
  })
}

const splitFile = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const CHUNK_SIZE = 10 * 1024 * 1024
  if (target.files && target.isDefaultNamespace.length > 0) {
    const file = target.files[0]
    const fileSize = file.size
    const md5hash = await calculateMD5(file)
    console.log(md5hash)

    const chunks = Math.ceil(fileSize / CHUNK_SIZE)
    const fileChunks = []
    let start = 0
    let end = CHUNK_SIZE
    console.log(end, fileSize)

    for (let i = 0; i < chunks; i++) {
      if (end > fileSize) {
        console.log('if', i)

        end = fileSize
      }
      const chunk = file.slice(start, end)
      console.log(chunk)

      fileChunks.push(chunk)
      start = end
      end = start + CHUNK_SIZE
    }
    console.log(fileChunks)
  }
}
</script>
<template>
 <input type="file" @change="splitFile">
</template>

错误原因

  1. 一次性加载大文件到内存:原代码通过FileReader.readAsArrayBuffer(file)把整个文件读入内存,再转成CryptoJS的WordArray。当文件超过200Mb时,生成的WordArray内部数组长度会超出JavaScript引擎的限制(V8引擎中,单个数组的最大长度受内存和引擎限制,大文件会导致数组长度超限)。
  2. V8引擎内存限制:即使系统剩余内存充足,V8引擎对单个对象的内存分配有上限,大文件一次性转成WordArray会触发这个限制,抛出数组长度无效的错误。

补充参考信息:

  • 即使可用堆内存充足,V8引擎也可能因为单个对象的内存上限抛出堆内存不足错误,大文件一次性处理极易触发。
  • JavaScript数组和类似对象存在长度上限,超过这个上限会直接抛出Invalid array length错误。

解决方法:分块计算MD5

不需要一次性加载整个文件,而是分块读取文件内容,逐步更新MD5哈希值,这样内存占用仅为单块大小,避免触发数组长度限制。

修改后的代码如下:

<script>
import CryptoJS from 'crypto-js'
const calculateMD5ByChunk = (file, chunkSize = 10 * 1024 * 1024) => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader()
    let offset = 0
    // 初始化MD5哈希对象
    let md5Hash = CryptoJS.algo.MD5.create()

    const processChunk = () => {
      if (offset >= file.size) {
        // 所有块处理完成,输出哈希值
        resolve(md5Hash.finalize().toString())
        return
      }
      // 切割当前块
      const chunk = file.slice(offset, offset + chunkSize)
      fileReader.readAsArrayBuffer(chunk)
      offset += chunkSize
    }

    fileReader.onload = function (e) {
      // 将当前块转成WordArray并更新哈希
      const wordArray = CryptoJS.lib.WordArray.create(e.target.result)
      md5Hash.update(wordArray)
      // 处理下一块
      processChunk()
    }

    fileReader.onerror = reject
    // 启动分块处理
    processChunk()
  })
}

const splitFile = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const CHUNK_SIZE = 10 * 1024 * 1024
  if (target.files && target.files.length > 0) { // 修正原代码中的判断错误
    const file = target.files[0]
    const fileSize = file.size
    const md5hash = await calculateMD5ByChunk(file, CHUNK_SIZE)
    console.log(md5hash)

    const chunks = Math.ceil(fileSize / CHUNK_SIZE)
    const fileChunks = []
    let start = 0
    let end = CHUNK_SIZE
    console.log(end, fileSize)

    for (let i = 0; i < chunks; i++) {
      if (end > fileSize) {
        end = fileSize
      }
      const chunk = file.slice(start, end)
      fileChunks.push(chunk)
      start = end
      end = start + CHUNK_SIZE
    }
    console.log(fileChunks)
  }
}
</script>
<template>
 <input type="file" @change="splitFile">
</template>

关键修改点

  1. 替换calculateMD5为calculateMD5ByChunk,分块读取文件并逐步更新MD5哈希。
  2. 使用CryptoJS.algo.MD5.create()创建可增量更新的哈希对象,每处理一块就调用update方法更新哈希。
  3. 修正原代码中的错误:target.isDefaultNamespace.length改为target.files.length,确保正确判断是否选择了文件。

内容的提问来源于stack exchange,提问作者Iven Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:55:25