如何用MapReduce脚本创建多CSV文件规避10MB文件大小限制?
解决方案
核心思路
由于无法提前获取未保存文件的实际大小,我们通过逐行累加内容并估算字节长度的方式,当累计大小接近10MB阈值时,立即保存当前文件并新建文件继续存储(每个文件保留表头),避免触发SSS_FILE_CONTENT_SIZE_EXCEEDED错误。同时优化CSV格式生成逻辑,避免特殊字符导致的格式错乱。
修改后的完整代码
function summarize(summary) { const datasetObj = dataset.load({"id": 'custdataset70'}); const headers = datasetObj.columns.map(col => col.label || col.id); // 转义表头字段,确保CSV格式合法 const escapedHeaders = headers.map(escapeCSVField).join(','); const headerWithNewline = `${escapedHeaders}\n`; const headerByteLength = getByteLength(headerWithNewline); const MAX_FILE_SIZE = 9.5 * 1024 * 1024; // 设为9.5MB留余量,避免超10MB限制 let currentContent = [escapedHeaders]; let currentByteLength = headerByteLength; let fileIndex = 1; const savedFileIds = []; // 逐行遍历数据,实时监控大小 summary.output.iterator().each((key, value) => { // 转义行字段,生成合法CSV行 const escapedRow = value.map(escapeCSVField).join(','); const rowWithNewline = `${escapedRow}\n`; const rowByteLength = getByteLength(rowWithNewline); // 若添加当前行后超出阈值,保存当前文件并重置内容 if (currentByteLength + rowByteLength > MAX_FILE_SIZE) { const fileId = saveCSVFile(currentContent.join('\n'), fileIndex); if (fileId) savedFileIds.push(fileId); // 重置内容,保留表头 currentContent = [escapedHeaders]; currentByteLength = headerByteLength; fileIndex++; } // 将当前行加入内容 currentContent.push(escapedRow); currentByteLength += rowByteLength; return true; }); // 保存最后一批剩余内容 if (currentContent.length > 1) { // 确保不止表头,有实际数据 const fileId = saveCSVFile(currentContent.join('\n'), fileIndex); if (fileId) savedFileIds.push(fileId); } else { log.debug('No Data', 'No unique dataset records found.'); return; } // 批量发送邮件(需调整sendEmail支持多文件ID) if (savedFileIds.length > 0) { sendEmail(savedFileIds); } } function saveCSVFile(csvContent, fileIndex) { const today = format.format({"value": new Date(), "type": format.Type.DATE}); // 文件名添加序号,避免同日期文件重名覆盖 const fileName = `DatasetResults_${today}_${fileIndex}.csv`; const csvFile = file.create({ "name": fileName, "fileType": file.Type.CSV, "contents": csvContent, "folder": 5081389 }); return csvFile.save(); } // 辅助函数:转义CSV字段,处理逗号、引号、换行符 function escapeCSVField(field) { if (typeof field !== 'string') field = String(field); if (field.includes(',') || field.includes('"') || field.includes('\n') || field.includes('\r')) { return `"${field.replace(/"/g, '""')}"`; } return field; } // 辅助函数:计算字符串UTF-8编码的字节长度 function getByteLength(str) { return new TextEncoder().encode(str).length; }
关键改动说明
- 字节长度估算:用
TextEncoder计算实际字节数,避免按字符数估算的误差(如中文占3字节)。 - 阈值预留空间:设置9.5MB作为拆分触发点,给文件元数据留足空间,确保最终文件不超10MB限制。
- CSV格式修复:新增
escapeCSVField函数处理特殊字符,防止字段含逗号、引号时导致列错位。 - 多文件命名:文件名添加序号后缀,避免同一日期下的文件重名覆盖。
- 实时拆分逻辑:遍历数据时实时监控大小,达到阈值立即保存并重置内容,避免一次性生成超大内容。
注意事项
- 若平台不支持
TextEncoder,可改用encodeURIComponent(str).split(/%..|./).length - 1估算字节数(精度稍低)。 - 需根据实际情况调整
sendEmail函数,使其支持接收多个文件ID数组,实现批量发送。
内容的提问来源于stack exchange,提问作者Maira S
相关产品推荐
相关产品推荐

