使用Node.js的csvtojson转换CSV到JSON:去除表头并解决多文件读取异常
问题:csvtojson读取多个CSV文件时表头被当作数据解析
我使用Node.js的csvtojson库读取CSV文件并转换为JSON,项目文件夹中有两个数据内容相同的CSV文件,尝试读取它们并转换为JSON后作为响应返回。但遇到问题:读取完第一个文件后,第二个文件的首行(列表头)被当作数据解析,导致JSON中出现形如{"Col 1":"Col 1","Col 2":"Col 2"...}的错误条目。
错误JSON示例
[ { "Col 1": "Test 1", "Col 2": "ABC 1", "Col 3": "DEF 1", "Col 4": "GHI 1" }, { "Col 1": "Test 2", "Col 2": "ABC 2", "Col 3": "DEF 2", "Col 4": "GHI 2" }, { "Col 1": "Test 3", "Col 2": "ABC 3", "Col 3": "DEF 3", "Col 4": "GHI 3" }, { "Col 1": "Col 1", // **问题所在** "Col 2": "Col 2", "Col 3": "Col 3", "Col 4": "Col 4" }, { "Col 1": "Test 1", "Col 2": "ABC 1", "Col 3": "DEF 1", "Col 4": "GHI 1" }, { "Col 1": "Test 2", "Col 2": "ABC 2", "Col 3": "DEF 2", "Col 4": "GHI 2" }, { "Col 1": "Test 3", "Col 2": "ABC 3", "Col 3": "DEF 3", "Col 4": "GHI 3" } ]
我的代码
import dotenv from 'dotenv'; import express from 'express'; import { Router } from 'express'; import fs from 'fs'; import { join } from "path"; import path from 'path'; import Converter from "csvtojson"; import fastcsv from 'fast-csv'; import Promise from 'bluebird'; Promise.promisifyAll(Converter.prototype); var converter = new Converter(); const router = Router(); dotenv.config(); router.get("/readfile", (req, res, next) => { const currDir = path.join('./outputfolder/'); console.log('currdir', currDir) function readFiles(dir, processFile) { // read directory fs.readdir(dir, (error, fileNames) => { if (error) throw error; fileNames.forEach(filename => { // get current file name const name = path.parse(filename).name; // get current file extension const ext = path.parse(filename).ext; // get current file path const filepath = path.resolve(dir, filename); // get information about the file fs.stat(filepath, function (error, stat) { if (error) throw error; // check if the current path is a file or a folder const isFile = stat.isFile(); // exclude folders if (isFile) { // callback, do something with the file processFile(filepath, name, ext, stat); } }); }); }); } readFiles(currDir, (filepath, name, ext, stat) => { // console.log('file path:', filepath); console.log('file name:', name); let csvData = []; converter .fromFile(filepath) .then((jsonObj) => { console.log(jsonObj); jsonObj.forEach(res => { if (res.UID !== '') { fs.writeFileSync('2pac.txt', JSON.stringify(jsonObj), (err) => { // throws an error, you could also catch it here if (err) throw err; }); } }) res.send(jsonObj) }) }); }) export { router };
解决方案
核心问题
你复用了同一个Converter实例。csvtojson的Converter实例在处理第一个文件后会保留表头解析状态,处理第二个文件时会跳过表头检测,直接把首行当作数据条目解析,导致表头被混入结果。
修复后的代码
import dotenv from 'dotenv'; import express from 'express'; import { Router } from 'express'; import fs from 'fs'; import path from 'path'; import Converter from "csvtojson"; import Promise from 'bluebird'; Promise.promisifyAll(Converter.prototype); const router = Router(); dotenv.config(); router.get("/readfile", async (req, res, next) => { const currDir = path.join('./outputfolder/'); console.log('currdir', currDir); // 改用异步方式读取目录和文件,方便收集所有结果 async function readAllFiles(dir) { const fileNames = await fs.promises.readdir(dir); const allResults = []; for (const filename of fileNames) { const filepath = path.resolve(dir, filename); const stat = await fs.promises.stat(filepath); if (stat.isFile()) { // 每个文件创建新的Converter实例 const converter = new Converter(); const jsonObj = await converter.fromFile(filepath); console.log(`处理完成:${filename}`); allResults.push(...jsonObj); // 写入文件:改为追加模式避免覆盖,也可统一写入一次 fs.appendFileSync('2pac.txt', JSON.stringify(jsonObj) + '\n', (err) => { if (err) console.error('写入文件失败:', err); }); } } return allResults; } try { const finalJson = await readAllFiles(currDir); res.send(finalJson); } catch (err) { console.error('处理文件出错:', err); res.status(500).send('读取文件失败'); } }) export { router };
关键改动说明
- 每个文件新建Converter实例:彻底避免实例状态复用导致的表头解析错误
- 改用异步/await处理流程:简化异步逻辑,确保所有文件处理完成后再统一发送响应(原代码会在第一个文件处理完就调用
res.send,导致后续响应失效) - 修复变量名冲突:原代码中
jsonObj.forEach(res => {})的res覆盖了路由响应对象,改为item避免冲突 - 优化文件写入逻辑:改用
appendFileSync避免重复覆盖,也可等所有文件处理完成后一次性写入提升性能 - 增加全局错误捕获:统一处理文件读取和转换过程中的异常,返回合适的HTTP状态码
内容的提问来源于stack exchange,提问作者user2542953
相关产品推荐
相关产品推荐

