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

基于Jquery实现服务器分块下载数据并追加至客户端文件

客户端分块追加写入CSV文件方案

我将数十万行JSON格式数据存储在Postgres服务器,需要实现分块下载功能:循环调用API拉取小批量数据,收到响应后立即追加到同一个CSV文件,避免在客户端缓存全量数据导致内存占用过高。当前代码每次调用都会生成新文件,无法实现追加写入。

原代码如下:

const writeDataToFile = (data) => {
    const rows = data.map((obj) => Object.values(obj).join(delimiter));
    const csvContent = rows.join('\n');
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    if (navigator.msSaveBlob) {
      navigator.msSaveBlob(blob, filename);
    } else {
      const link = document.createElement('a');
      if (link.download !== undefined) {
        const url = URL.createObjectURL(blob);
        link.setAttribute('href', url);
        link.setAttribute('download', filename);
        link.setAttribute('target', '_blank');
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      }
    }
  };

解决方案

现代浏览器方案(推荐):使用FileSystemAccess API

该API支持直接在用户选择的本地文件中追加内容,无需缓存全量数据,内存占用极低,适用于Chrome、Edge等现代浏览器。

  1. 获取文件句柄
async function getFileHandle() {
  const options = {
    types: [
      {
        description: 'CSV文件',
        accept: {
          'text/csv': ['.csv'],
        },
      },
    ],
  };
  const handle = await window.showSaveFilePicker(options);
  return handle;
}
  1. 实现追加写入逻辑
async function appendToFile(handle, content, isFirstWrite = false) {
  const writable = await handle.createWritable();
  // 首次写入时添加表头
  if (isFirstWrite) {
    const headers = Object.keys(content[0]).join(',');
    await writable.write(headers + '\n');
  }
  // 转换数据为CSV行并追加
  const rows = content.map(obj => Object.values(obj).join(',')).join('\n');
  await writable.write(rows + '\n');
  await writable.close();
}
  1. 分块下载主流程
async function downloadChunks(apiUrlTemplate, totalChunks) {
  const fileHandle = await getFileHandle();
  let isFirstWrite = true;

  for (let i = 0; i < totalChunks; i++) {
    // 替换为你的分页API请求逻辑
    const response = await fetch(`${apiUrlTemplate}?page=${i+1}&pageSize=1000`);
    const data = await response.json();
    
    await appendToFile(fileHandle, data, isFirstWrite);
    isFirstWrite = false;

    // 可添加进度提示
    console.log(`已完成第${i+1}/${totalChunks}块数据写入`);
  }

  alert('文件下载完成');
}

旧浏览器兼容方案:增量构建Blob

如果需要兼容不支持FileSystemAccess API的旧浏览器,可以采用增量构建Blob的方式(仍会占用一定内存,但比全量缓存小):

let blobParts = [];
let isFirstWrite = true;

async function downloadChunksLegacy(apiUrlTemplate, totalChunks) {
  for (let i = 0; i < totalChunks; i++) {
    const response = await fetch(`${apiUrlTemplate}?page=${i+1}&pageSize=1000`);
    const data = await response.json();

    let csvContent = '';
    // 首次写入添加表头
    if (isFirstWrite) {
      const headers = Object.keys(data[0]).join(',');
      csvContent += headers + '\n';
      isFirstWrite = false;
    }
    const rows = data.map(obj => Object.values(obj).join(',')).join('\n');
    csvContent += rows + '\n';

    blobParts.push(new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }));
    console.log(`已完成第${i+1}/${totalChunks}块数据处理`);
  }

  // 合并Blob并生成下载链接
  const finalBlob = new Blob(blobParts, { type: 'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(finalBlob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'data.csv';
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:23:13