如何在处理 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 文件同步加载到内存中的主要内容,如果未能解决你的问题,请参考以下文章

如何在 http post 请求中发送大型 csv

异步处理http请求同步返回结果

如何在 ssis 中处理之前检查 csv 文件中的文件结尾

如何在导入 R 之前预处理 CSV 文件?

如何同步ExCeL与PS变量

python中如何将csv文件转为xls文件