如何在处理 HTTP 请求之前将 csv 文件同步加载到内存中
Posted
技术标签:
【中文标题】如何在处理 HTTP 请求之前将 csv 文件同步加载到内存中【英文标题】:How to synchronously load a csv file into memory before handling HTTP requests 【发布时间】:2019-08-18 19:42:15 【问题描述】:我正在尝试编写一个简单的 express/node.js 应用程序,该应用程序使用 csv 文件中的数据响应 GET 请求。我想读取这个 csv 文件来生成一个 javascript 对象(本质上是一个键值映射),然后使生成的映射可用于控制器中的 HTTP 请求处理逻辑。
我编写了一个读取 csv 文件并导出所需对象的模块,但我不确定如何确保:
-
此操作完成,对象在处理 HTTP 请求之前实际存在
文件操作仅在服务器启动时执行一次,而不是每个请求执行一次,从而导致大量开销
如何组织我的代码以在 express 应用的上下文中实现这些目标?
这就是我处理 CSV 文件的方式:
var myMap = ;
fs.createReadStream('filename.csv')
.pipe(csv())
.on('data', (row) =>
// Build javascript object
myMap[row['key']] = row['value'];
)
.on('end', () =>
console.log('Done.');
);
// Does this work?
module.exports = myMap;
【问题讨论】:
【参考方案1】:在文件加载到内存后确保http对象监听如何:
// server.js
var myMap = ;
function readCsv(cb)
fs.createReadStream('filename.csv')
.pipe(csv())
.on('data', (row) =>
// Build javascript object
myMap[row['key']] = row['value'];
)
.on('end', () =>
console.log('Done.');
cb();
);
var app = express();
exports = Object.freeze(
server: http.createServer(app)
init()
readCsv(() =>
this.server.listen(80)
)
)
类似的东西。
你也可以使用 Promise
// server.js
var myMap = ;
function readCsv()
return new Promise((resolve, reject) =>
fs.createReadStream('filename.csv')
.pipe(csv())
.on('data', (row) =>
// Build javascript object
myMap[row['key']] = row['value'];
)
.on('end', () =>
console.log('Done.');
resolve();
)
.on('error', reject)
)
var app = express();
exports = Object.freeze(
server: http.createServer(app)
init()
return readCsv().then(() =>
this.server.listen(80)
)
)
【讨论】:
我终于明白了如何使用自定义 Promise 来处理异步代码。谢谢!【参考方案2】:我会寻找更同步的方式来读取文件和处理 http 请求。这是它应该是什么样子的示例代码,
import fs from 'fs';
async function processCSV()
try
let map = await readCsv();
//handle http request in another function with same async await way
let http = await processHttpRequest(map);
// process the http response
catch (e)
console.log('e', e);
function readCsv()
let myMap = [];
fs.createReadStream('filename.csv')
.pipe(csv())
.on('data', (row) =>
// Build javascript object
return myMap[row['key']] = row['value'];
)
.on('end', () =>
console.log('Done.');
);
async function processHttpRequest(map)
try
let reqres = await httpReuqest(map); // Your defined function for httpReuqest
catch (e)
processCSV();
processHttpReuqet();
【讨论】:
【参考方案3】:为了实现这两个目标,您可以将代码包含在 app.js 文件中。 App.js 仅在快速服务器启动时运行。它不会在页面刷新时重新加载。您可以在 readstream 结束后运行 app.listen。
var myMap = ;
fs.createReadStream('filename.csv')
.pipe(csv())
.on('data', (row) =>
// Build javascript object
myMap[row['key']] = row['value'];
)
.on('end', () =>
app.listen(port, () => console.log(`Example app listening on port $port!`));
);
但是,由于我认为您不会拥有大量数据,因此对于 csv 解析器和文件读取器,最好使用同步(阻塞)方法。这只会让它更容易理解。我在下面使用csv-parse。
const express = require('express')
const fs = require('fs')
const parse = require('csv-parse/lib/sync')
const app = express()
const port = 3000
/* In this example assume myMap will be
/ `
/ "key_1","key_2"
/ "value 1","value 2"
/ `
*/
var myMap = fs.readFileSync('sample.csv', 'utf8');
/* parsing the csv will return:
/ [Object key_1: "value 1", key_2: "value 2"]
*/
const records = parse(myMap,
columns: true,
skip_empty_lines: true
)
app.get('/', (req, res) => res.send('Hello World!' + records[0].key_1))
app.listen(port, () => console.log(`Example app listening on port $port!`))
test it on runkit
【讨论】:
【参考方案4】:更新:
使用https://csv.js.org/parse/
以下一个已弃用,不再维护。
已弃用:
您好,我创建了一个 npm 包来同步读取 CSV 或作为承诺:
https://www.npmjs.com/package/csv-parser-sync-plus-promise
说明:
csv-parser-sync-plus-promise
一个同步读取 csv 或作为 promise 的模块
特点
现在同步读取任何 csv 或作为 promise。选择是你的
用法
let parser = require('csv-parser-sync-plus-promise')
// 用于同步
let a=parser.readCsvSync('<filepath>')
// 承诺
let b=parser.readCsvPromise('<filepath>')
**Note:** You can use both fully qualified and relative paths <filepath>
错误
所有错误都将打印为 console.error 并且进程将退出并退出代码 222
【讨论】:
我尝试将您的库作为 csv-parser 的直接替代品来解决这种确切类型的问题。不幸的是,在 csv-parser 在 1 秒内异步处理 1000 行文件的地方,您的库似乎挂了很长时间。不知道怎么了。不过我喜欢这个想法,尤其是在尝试使用从 CSV 加载的异步样本数据来设置异步 Jest 测试时。 @JasonD hi 使用 csv-parse @JasonD 我犯了一个更好的模块csv.js.org/parse 所以我的不再维护了以上是关于如何在处理 HTTP 请求之前将 csv 文件同步加载到内存中的主要内容,如果未能解决你的问题,请参考以下文章