在 node.js 中读取 csv 文件的内容
Posted
技术标签:
【中文标题】在 node.js 中读取 csv 文件的内容【英文标题】:Reading contents of csv file in node.js 【发布时间】:2014-11-28 05:41:22 【问题描述】:我正在尝试在 nodejs 中实现一个模块(刚开始在 nodejs 中工作),它的要求如下
-
上传 .csv 文件。
读取 csv 文件的内容。
目前用于restful api的框架是“express”:“~4.2.0”和multer用于文件上传。
现在我在 app.js
中配置了 multer,如下所示app.use(multer(
onFileUploadData : function(file, data)
console.log('onFileUploadData Called with data - '+ data);
));
在我的路由文件中,我有一个如下所示的 post 端点
app.post('/sample.csv',lead.processCSV);
这条路由是从下面的 ajax 调用中调用的
$.ajax(
xhrFields: withCredentials: true,
url: '/sample.csv',
type: 'POST',
success: function (data)
$scope.handleResponse(data);
,
error: function (error, xhr)
angular.element('#csvUploadBusyIcon').hide();
alert('Oops! Upload failed');
,
data: formData,
cache: false,
contentType: false,
processData: false
);
现在我想获取 csv 文件的内容,即当所有内容都已加载后,我应该处理我的 lead.processCSV 方法。
我还需要任何其他用于 csv 文件的模块,或者 multer 在我的情况下就足够了吗?
任何正确方向的建议/指导都会有所帮助。提前致谢。
【问题讨论】:
【参考方案1】:有一个很棒的节点项目对我帮助很大。你应该check it out 我们要使用的是他们的 csv-parse 模块。它能够获取一个流作为输入并逐行读取它而不会阻塞事件循环,因此基本上在您处理文件时您的服务器不会卡住,其他请求仍然可以正常处理。
既然你说你只是从 nodejs 开始,你应该快速搜索并了解中间件在请求处理过程中是如何工作的。 作为请求处理的简化,中间件是一个函数(req, res, next)。使用 req 您可以获得请求数据。使用 res 您可以发送响应,然后将您的 req 和 res 对象发送到下一个中间件。这样您就可以分部分处理请求,并且流的最后一个中间件将向客户端发送响应(例如 res.send(200))
Multer(...) 调用返回一个中间件函数。当请求到达此中间件时,multer 将尝试下载用户在发布请求中发送的任何文件。当您说 app.use(Multer(...)) 时,您是在要求 multer 尝试从任何包含文件的发布请求中下载文件。如果不是所有路由都需要上传文件,这会带来安全风险。
好的,话虽如此,这是我为处理您的用例而编写的示例代码:
//Important Security advice:
//don't add multer as a middleware to all requests.
//If you do this, people will be able to upload files
//in ALL YOUR 'post' handlers!!!
var Multer = require('multer');
var Parse = require('csv-parse');
var fs = require('fs')
function parseCSVFile(sourceFilePath, columns, onNewRecord, handleError, done)
var source = fs.createReadStream(sourceFilePath);
var linesRead = 0;
var parser = Parse(
delimiter: ',',
columns:columns
);
parser.on("readable", function()
var record;
while (record = parser.read())
linesRead++;
onNewRecord(record);
);
parser.on("error", function(error)
handleError(error)
);
parser.on("end", function()
done(linesRead);
);
source.pipe(parser);
//We will call this once Multer's middleware processed the request
//and stored file in req.files.fileFormFieldName
function parseFile(req, res, next)
var filePath = req.files.file.path;
console.log(filePath);
function onNewRecord(record)
console.log(record)
function onError(error)
console.log(error)
function done(linesRead)
res.send(200, linesRead)
var columns = true;
parseCSVFile(filePath, columns, onNewRecord, onError, done);
//this is the route handler with two middlewares.
//First: Multer middleware to download file. At some point,
//this middleware calls next() so process continues on to next middleware
//Second: use the file as you need
app.post('/upload', [Multer(dest:'./uploads'), parseFile]);
我希望这会有所帮助。确保了解路由中间件在节点中的工作方式:它们是高质量代码的关键。
马塞尔
【讨论】:
感谢 Marcel 的回答,有没有什么东西可以在没有任何包的情况下处理 csv 文件?需要很长时间吗?【参考方案2】:我有一个类似的请求来处理 csv 文件,我尝试实施您的解决方案:它可以工作,但只要我将它与控制台日志一起使用。我试图将“记录”变量存储在一个名为“结果”的数组中,但我得到了一个空数组 [],在呈现这个空数组之后,我收到了 console.log 响应,其中显示了解析后的 CSV 数据。
所以这似乎是同步的问题。我的意思是,处理 csv 文件需要一段时间。所以我尝试压缩你的代码并将其转换为 Promise 然后执行它。所以,在 promise 执行之后,我的数组就可以使用了。
-
注意:我是初学者,所以它可能包含一些错误。到目前为止,它对我来说工作正常。
注意:我的 CSV 测试文件的内容是:
title, type, value, category
Loan, income, 1500, Others
Website Hosting, outcome, 50, Others
Ice cream, outcome, 3, Food
注意:与您的情况有一些不同:我从 rote '/import.我正在使用 Insomnina Designer 应用程序发送一个多部分表单正文,其中包含一个名为 importFile 的文件
注意:我导入了你使用的相同库,并且我还使用了中间件的概念
注意:在这种情况下,我只需要一个文件,所以我使用了 multer(dest: './upload').single('importFile')。它也可以用于 .any()。
注意:我使用的是打字稿,所以对于 JS 来说,只需在一些变量声明后删除即可:@type,例如
注意:我留下了选项 1 - 仅使用数组和选项 2 - 使用对象。
const results: object[] = [];
becomes:
const results = [];
让我们进入代码:
import Router, Request, Response from 'express';
import csv from 'csv-parse';
import multer from 'multer';
import fs from 'fs';
// used on option 2 due typescript
interface CSVTransactionDTO
title: string;
value: number;
type: 'income' | 'outcome';
category: string;
app.post(
'/import', // route name
multer( dest: './upload' ).single('importFile'), // middleware to download one file (csv)
async (request: Request, response: Response) => //last middleware with CSV parsing with arrow function
const filePath = request.file.path;
let rowCounter = 0;
const results: string[] = [];// option 1
const newTransactions: CSVTransactionDTO[] = [];// option 2
function parseCSVPromise(): Promise<void>
return new Promise((resolve, reject) =>
const ConfigCSV =
// delimiter:';',//other delimiters different from default = ','
from_line: 2, // data starts here
trim: true, // ignore white spaces immediately around the delimiter (comma)
;
fs.createReadStream(filePath)
.pipe(csv(ConfigCSV))
.on('data', /* async */ row =>
rowCounter += 1;// counter of how many rows were processed
// console.log(data); // just test
results.push(row); // Option1 - The simplest way is to push a complete row
const [title, type, value, category] = row;// Option2, process it as an object
newTransactions.push(title, type, value, category);// Option2, process it as an object
)
.on('error', error =>
reject(error);
throw new Error('Fail to process CSV file');
)
.on('end', () =>
resolve();// ends the promise when CSV Parse send 'end' flag
);
);
await parseCSVPromise(); // now using the created promise - await finishing parsingCSV
console.log('option1', results);// option1
console.log('option2',newTransactions);// option2
return response.json( resultsCounter, results ); // For testing only - interrupting the rote execution
// continue processing results and send it to dataBase...
//await fs.promises.unlink(filePath); // optionally you can delete the file parsed/processed
选项 1 响应:
[
[ 'Loan', 'income', '1500', 'Others' ],
[ 'Website Hosting', 'outcome', '50', 'Others' ],
[ 'Ice cream', 'outcome', '3', 'Food' ]
]
选项 2 响应:
[
title: 'Loan', type: 'income', value: '1500', category: 'Others' ,
title: 'Website Hosting', type: 'outcome', value: '50', category: 'Others' ,
title: 'Ice cream', type: 'outcome', value: '3', category: 'Food'
]
【讨论】:
以上是关于在 node.js 中读取 csv 文件的内容的主要内容,如果未能解决你的问题,请参考以下文章
Node.js:如何在提交时读取用户选择选项并在 textarea 中提供文件内容
如何让运行 Node.js 脚本的 cron 作业从 .env 文件中读取变量?
如何使用 HTML 输入文件导入 excel 文件并在 Node.js 中读取文件内容(如何将完整路径发送到 Node.js)