node fs 导出 csv

3,396 阅读4分钟

这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战

一点感悟

我发现身边很多朋友,在做 node 开发的时候,如果遇到一个此前没做过的需求,会有两种表现:

  • 第一种表现就是问度娘,好一点的问谷歌
  • 第二种表现是问别人

首先说问别人,最后可能得到一个思路,但有时候可能也让你更加的模棱两可,因为你此前根本没有对 API 的认知,也没有对实现思路进行基本思考,在这种情况下把别人的思路强加给你,无益于你的需求实现

而直接百度或者谷歌,其实和问别人一样,得到的都是别人的思路,唯一不同点在于,在这个检索过程中,你会进行思考,形成基础的思维。

但我结合自身的经验,发现了一个问题:

通常情况下,在我们拿到某个需求,却完全不知道从何下手的时候,其实我们已经在脑子里检索了一遍,当我们的知识储备没有发现任何能用于实现这个需求的相关知识,就会束手无策。

举个例子:

假设我现在要做一个导出 csv 文件的需求,如果我不知道 node 中 fs 这个文件系统,那我可能直接就懵了,因为在前端我知道<a download="**" href="..."></a>这种可以用来下载,但是在 node 中没有这种东西啊~

所以我就懵了,就不知道怎么办,就只能问百度,然后人家说,fs 可以写文件,这时候我又去查 fs 这个 API,然后在 csdn、思否上各种看,嗯,好像明白了,其实这本质上就是一个 cv 的过程,你实现了这个需求以后,美滋滋的下班了

那么这时候你在路上等公交的时候,你想你这一天完成的需求,你能独立的讲出 fs 它是做什么的吗?它有几个常用的方法呢?都是怎么用的呢?你这工作了一天,学了什么新的东西吗?

所以,真正的问题在于,我的知识面不够广,知识储备的不够深,完完全全照顾不到日常的开发需求了。如果我对 fs 这个文件系统有一点基础的印象或者认知,我就直接去看文档就好了。

言归正传

node 的 fs 文件系统是非常常用的模块,可以用来非常方便的对文件、文件夹进行增删改查读写等操作。

使用 fs 不需要额外的安装,直接引入就可以了,并且 fs 提供了多种引入和使用的方法。

  • 基于回调函数的异步
import * as fs from 'fs';
// or
import { unlink } from 'fs';

因为像是文件读写这种操作,都是异步操作,所以才会使用回调函数,并且,node 遵循错误优先的原则,在回调中第一个参数往往是 ERROR 对象,用来在操作异常时捕获异常,如果操作没有异常,则第一个参数为null或者undefined

unlink('./hello.txt', (err) => {
  if (err) throw err;
  console.log('successfully deleted ./hello.txt');
});
  • 基于 promise API 的异步
import * as fs from 'fs/promises';
// or
import { unlink } from 'fs/promises';

promise 的出现使得我们可以以同步的逻辑编写异步代码,很大程度上解决了回调地狱的问题,虽然写法简单,但是 promise API 不能捕获异常,需要借助于try{}catch(){}语句。

try {
  await unlink('./hello.text');
  console.log('successfully deleted ./hello.text');
} catch (error) {
  console.error('there was an error:', error.message);
}

使用 promise API 需要额外的注意:

Promise API 使用底层的 Node.js 线程池在事件循环线程之外执行文件系统操作。 这些操作不是同步的也不是线程安全的。 对同一文件执行多个并发修改时必须小心,否则可能会损坏数据。

  • 同步的写法

同步的代码会阻止 Node.js 事件循环和后面的 JavaScript 代码执行,直到同步的操作完成。所以一般情况下谨慎使用或者不用。

import { unlinkSync } from 'fs';

try {
  unlinkSync('./hello.text');
  console.log('successfully deleted ./hello.text');
} catch (err) {
  console.error('there was an error:', error.message);
}

导出 csv

在程序开发中,时常需要将数据导出为 csv,txt,甚至 pdf 等文件,供用户进行数据查看或分享。

下面,让我们用 fs 来实现,如何将数据导出为 csv 文件。

  1. 新建文件夹 node-csv
  2. 在文件夹内新建文件 demo.js
  3. 用编辑器打开,编辑 demo.js

const { promises: { readFile, writeFile, mkdir } } = require('fs');

(async () => {
  // 创建模拟数据
  let list = []
  for (let i = 0; i < 10; i += 1) {
    list.push({
      id: i,
      name: '小明',
      age: 18,
      address: '北京市海淀区农业科学院',
      phone: '13313366789',
    })
  }
  /*
   * 生成表头,\ufeff 是防止乱码
   * csv中以 `,` 换列,`\n`换行
   */ 
  let title = Object.keys(list[1])
  let csvContent = '\ufeff' + title.join(',') + '\n'
  
  // 添加表体
  list.forEach((item, index) => {
    let c = Object.values(item).join(',') + '\n'
    csvContent += c
  })
  // 生成文件夹存储生成的文件
  await mkdir('download')

  // 生成csv文件
  await writeFile('./download/data.csv', csvContent)

  // 生成JOSN
  await writeFile('./download/data.json', JSON.stringify(list))
  console.log('File generated successfully,open download to check')
})()

保存后在 cmd 或者 terminal 中运行如下命令

node demo

当你看到这样的提示

ExperimentalWarning: The fs.promises API is experimental
File generated successfully,open download to check

就说明我们的生成 csv 成功了,然后 node-csv,接着打开 download 文件夹,查看生成的 csv 和 json 文件即可。

在这里插入图片描述 在这里插入图片描述

如果想了解 fs 的 promise ,或者如何生成 txt,请点击这里

码字不易,送一个赞可好~~