如何在JavaScript中读取两个独立CSV文件并实现数据关联?
解决两个CSV文件读取后关联合并的问题
原代码的核心问题
project和participants变量在for循环内部声明,每次循环都会重置,异步读取完成后无法保留有效数据FileReader是异步操作,循环执行完毕时文件可能还没读取完成,此时调用合并逻辑会拿到空值
修改后的完整实现
HTML部分(保持不变)
<form id="categoryform"> <input type="file" id="projectCsvFileInput" multiple><br><br> <input type="submit"> </form>
JavaScript部分(修复异步问题+添加合并逻辑)
// 全局存储两个文件的数据,避免循环内变量重置 let projectData = []; let participantsData = []; // 计数器:统计已读取完成的文件数量 let loadedFileCount = 0; categoryform.addEventListener("submit", function (e) { e.preventDefault(); // 每次提交重置数据和计数器 projectData = []; participantsData = []; loadedFileCount = 0; const uploadedFiles = projectCsvFileInput.files; // 先校验是否上传了两个文件 if (uploadedFiles.length !== 2) { alert("请上传两个CSV文件"); return; } // 遍历处理每个文件 for (let i = 0; i < uploadedFiles.length; i++) { const file = uploadedFiles[i]; const reader = new FileReader(); reader.onload = function(event) { const fileContent = event.target.result; // 根据表头区分文件类型 if (fileContent.includes('Project Name')) { projectData = csvToArr(fileContent, ","); } else { participantsData = csvToArr(fileContent, ","); } loadedFileCount++; // 两个文件都读取完成后,执行合并逻辑 if (loadedFileCount === 2) { // 这里传入关联字段,比如用"Project Name"作为匹配键 const mergedResult = mergeCsvByKey(projectData, participantsData, "Project Name"); console.log("合并后的数据:", mergedResult); // 可在这里添加后续处理,比如渲染到页面、导出等 } }; reader.readAsText(file); } }); // CSV转数组对象的工具函数(优化了字符清理逻辑) function csvToArr(stringVal, splitter) { const [headerKeys, ...rows] = stringVal .trim() .split("\n") .map(item => item.split(splitter)); return rows.map(row => { const rowObj = {}; headerKeys.forEach((key, index) => { // 清理多余的换行符、引号和无效字符 const cleanKey = key.replace('\r', '').trim(); const cleanValue = row[index]?.replace('\r', '').replace('"', '').replace('/S', '').trim() || ""; rowObj[cleanKey] = cleanValue; }); return rowObj; }); } // 基于指定字段关联合并两个CSV数据的函数 function mergeCsvByKey(projectList, participantList, joinKey) { // 将项目数据转为Map,提升匹配效率 const projectMap = new Map(); projectList.forEach(project => { const keyValue = project[joinKey]; if (keyValue) projectMap.set(keyValue, project); }); // 遍历参与者数据,匹配对应项目信息并合并 return participantList.map(participant => { const matchedProject = projectMap.get(participant[joinKey]) || {}; // 合并对象,参与者字段会覆盖项目中同名字段(如有) return { ...matchedProject, ...participant }; }); }
关键优化点
- 新增文件数量校验,避免用户上传数量不符
- 用计数器等待所有异步读取完成后再执行合并,解决异步时序问题
- 使用
Map存储项目数据,比嵌套循环匹配效率更高 - 优化CSV解析的字符清理逻辑,减少无效数据干扰
内容的提问来源于stack exchange,提问作者meijiOrO
相关产品推荐
相关产品推荐

