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

如何用JavaScript在浏览器前端将文件拆分为40KB分片后上传

前端文件分片上传实现方案与优化建议

我之前做过不少前端分片上传的项目,先聊聊你当前用base64拆分的痛点——base64编码会让文件体积膨胀约33%,也就是说你设定的40KB base64分片,对应的原始二进制数据其实只有~30KB,这会白白增加上传的数据量和前端编码、后端解码的额外开销。如果没有特殊场景限制,优先推荐直接操作二进制Blob/ArrayBuffer分片,效率会高很多。下面给出具体实现方案和优化思路:

一、核心实现方案:二进制Blob分片(推荐)

直接利用浏览器原生的File.slice()方法切割文件为Blob分片,无需转base64,从根源避免体积膨胀和编码开销。

实现步骤

  1. 获取用户选择的文件,生成唯一文件标识(用于服务器合并分片)
  2. 按40KB的大小计算分片总数
  3. 循环切割文件为Blob分片,逐个/并发上传
  4. 所有分片上传完成后,通知服务器合并文件

代码示例

const CHUNK_SIZE = 40 * 1024; // 40KB 分片大小(字节)

async function uploadFile(file) {
  const fileSize = file.size;
  const totalChunks = Math.ceil(fileSize / CHUNK_SIZE);
  // 生成唯一文件ID,避免同名文件冲突
  const fileId = `${file.name}-${Date.now()}-${Math.random().toString(36).slice(2)}`;

  for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
    const start = chunkIndex * CHUNK_SIZE;
    const end = Math.min(start + CHUNK_SIZE, fileSize);
    // 直接切割文件为Blob分片
    const chunk = file.slice(start, end);

    // 构造FormData,和普通文件上传格式一致
    const formData = new FormData();
    formData.append('fileChunk', chunk);
    formData.append('fileId', fileId);
    formData.append('chunkIndex', chunkIndex);
    formData.append('totalChunks', totalChunks);
    formData.append('fileName', file.name);

    // 上传分片(这里用fetch示例,也可以用XMLHttpRequest)
    const response = await fetch('/api/upload-chunk', {
      method: 'POST',
      body: formData
    });

    if (!response.ok) {
      throw new Error(`第${chunkIndex + 1}个分片上传失败,请重试`);
    }
  }

  // 所有分片上传完成,请求服务器合并文件
  const mergeResponse = await fetch('/api/merge-file', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      fileId,
      fileName: file.name,
      totalChunks
    })
  });

  if (mergeResponse.ok) {
    console.log('文件上传完成!');
    // 这里可以添加成功提示或页面跳转逻辑
  }
}

// 绑定文件选择事件
document.getElementById('file-input').addEventListener('change', (e) => {
  const selectedFile = e.target.files[0];
  if (selectedFile) {
    uploadFile(selectedFile).catch(err => alert(err.message));
  }
});

二、若必须使用base64的优化方案

如果因为后端接口限制等原因必须用base64上传,可通过以下方式减少浪费:

  • 计算对应原始二进制的分片大小:base64每3字节原始数据转4字符,所以40KB的base64对应的原始二进制大小为 40*1024 * 3/4 = 30720字节(30KB),按这个大小切割原始文件,转base64后刚好不超过40KB。
  • 避免一次性转整个文件为base64:大文件一次性转base64会占用大量内存,应分片读取转码。

代码示例

const MAX_BASE64_CHUNK_SIZE = 40 * 1024; // 目标base64分片大小
const RAW_CHUNK_SIZE = Math.floor(MAX_BASE64_CHUNK_SIZE * 3 / 4); // 对应原始二进制大小

async function uploadFileWithBase64(file) {
  const fileSize = file.size;
  const totalChunks = Math.ceil(fileSize / RAW_CHUNK_SIZE);
  const fileId = `${file.name}-${Date.now()}-${Math.random().toString(36).slice(2)}`;

  for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
    const start = chunkIndex * RAW_CHUNK_SIZE;
    const end = Math.min(start + RAW_CHUNK_SIZE, fileSize);
    const chunk = file.slice(start, end);

    // 分片转base64(去掉dataURL前缀)
    const base64Data = await new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result.split(',')[1]);
      reader.onerror = reject;
      reader.readAsDataURL(chunk);
    });

    // 上传base64数据
    const response = await fetch('/api/upload-base64-chunk', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        fileId,
        chunkIndex,
        totalChunks,
        fileName: file.name,
        base64Data
      })
    });

    if (!response.ok) {
      throw new Error(`第${chunkIndex + 1}个分片上传失败`);
    }
  }

  // 发起合并请求
  const mergeResponse = await fetch('/api/merge-file', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      fileId,
      fileName: file.name,
      totalChunks
    })
  });

  if (mergeResponse.ok) {
    console.log('文件上传完成!');
  }
}

三、通用优化建议(提升体验与可靠性)

不管用哪种分片方式,这些优化都能大幅提升上传体验:

  • 断点续传:上传前先请求服务器,获取当前文件已上传的分片索引,跳过已上传的分片(需要服务器记录每个fileId对应的已上传分片)。
  • 并发上传:不要串行上传,可控制同时上传3-5个分片(用Promise.all限制并发数),提升上传速度,注意不要超过服务器的并发限制。
  • 进度跟踪:监听每个分片的上传进度,计算整体上传进度(已上传分片大小总和/文件总大小),实时展示给用户。
  • 分片校验:每个分片计算MD5/SHA1哈希,上传时一起发送给服务器,服务器验证分片完整性,避免损坏。
  • 错误重试:分片上传失败时自动重试3次,仍失败再提示用户手动重试。
  • 大文件内存优化:对于GB级大文件,始终用File.slice()流式处理,避免一次性读取过多数据导致内存溢出。

内容的提问来源于stack exchange,提问作者Patoshi パトシ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:11:05