本文为 Node.js 系列笔记第二篇。文章参考:nodejs 教程 —— 大地;《深入浅出 Node.js》;阮一峰 nodejs 博客; 添加链接描述

文章目录

  • 一、fs 模块常用读写操作
    • 1. fs.start: 判断文件 or 目录
    • 2. fs.mkdir: 创建目录
    • 3. fs.writeFile: 写入数据
    • 4. fs.appendFile: 追加数据
    • 5. fs.readFile: 读取文件内容
    • 6. fs.readdir: 读取文件目录
    • 7. fs.rename: 重命名
    • 8. fs.rmdir: 删除目录
    • 9. fs.unlink: 删除文件
    • 10. fs 模块应用
  • 二、async 与 await
  • 三、fs 中的流
    • 1. fs.createReadStream
    • 2. fscreateWriteStream()
    • 3. 管道流

一、fs 模块常用读写操作


fs 是 filesystem 的缩写,该模块主要用于对系统文件及目录进行读写操作,它是 Node 的内置模块。下面介绍一下相关的常用 API 。

1. fs.start: 判断文件 or 目录


检测是文件还是目录。示例如下:

const fs = require('fs');fs.stat('./html', (err, stats) => {if (err) {console.log(err);return;}console.log(`是否为文件:${stats.isFile()}`);            // 是否为文件:falseconsole.log(`是否为目录:${stats.isDirectory()}`);       // 否为目录:true
})

2. fs.mkdir: 创建目录


以异步的方式用于创建目录。mkdir 接受三个参数。

fs.mkdir(path, [mode], [callback(err)])
  1. path:将创建的目录路径
  2. mode:可选。目录权限(读写权限),默认0777
  3. callback :可选。回调函数,传递异常参数err
  • 示例
 const fs = require('fs');fs.mkdir('./css', (err) => {if (err) {console.log(err);return;}console.log('创建成功');    // 创建成功})

3. fs.writeFile: 写入数据


以异步的方式创建文件并将 data 写入文件,文件已存在的情况下,原内容将被替换。

fs.writeFile(filename, data, [options], [callback(err)])
  1. filename :文件名称

  2. data (String | Buffer) :将要写入的内容,可以使字符串或 buffer 数据。

  3. options (Object):可选。option 数组对象,包含:

    1)encoding :可选。默认 ‘utf8′,当 data 使 buffer 时,该值应该为 ignored。
    2)mode:文件读写权限,默认值 438
    3)flag:默认值 ‘w’

  4. callback:可选。回调函数,传递一个异常参数 err。

  • 示例
 const fs = require('fs');fs.writeFile('./html/index.html', 'Hello World', (err) => {if (err) {console.log(err);return;}console.log('写入文件成功');        // 写入文件成功})

4. fs.appendFile: 追加数据


将 data 插入到文件里,如果文件不存在会自动创建。与 fs.writeFile 的区别是,如果文件存在原内容不会被覆盖,而是进行追加。

fs.appendFile(filename, data, [options], callback)
  • 示例
 const fs = require('fs');fs.appendFile('./html/index.html', '\nnode.js', (err) => {if (err) {console.log(err);return;}console.log('appendFile 成功');})

5. fs.readFile: 读取文件内容


以异步的方式读取文件内容。不置顶内容编码的情况下,将以 buffer 的格式输出,如:<Buffer 32 33 31 32 33 31 32 33 31 32 33>

fs.readFile(filename, [encoding], [callback(err,data)])
  1. filename:文件路径
  2. options:可选。option 对象,包含 encoding,编码格式。
  3. callback:可选。回调函数,2 个参数,异常 err 和文件内容 data(Buffer)。
  • 示例
 const fs = require('fs');fs.readFile('./html/index.html', (err, data) => {if (err) {console.log(err);return;}console.log(data);  // 打印 <Buffer 48 65 6c 6c 6f 20 57 6f 72 6c 64 0a 6e 6f 64 65 2e 6a 73>});

可以利用 toString() 将 Buffer 类型转换为 String:

    console.log(data.toString());// Hello World// node.js

6. fs.readdir: 读取文件目录


以异步的方式读取文件目录。

fs.readdir(path, [callback(err,files)])
  1. path:目录路径。
  2. callback :可选。回调函数,传递两个参数 err 和 files(string[]),files 是一个包含 “ 指定目录下所有文件名称的” 数组。
  • 示例
 const fs = require('fs');fs.readdir('./day04', (err, files) => {if (err) {console.log(err);return;}console.log(files);     // [ 'index.html' ]})

7. fs.rename: 重命名


修改文件名称,可更改文件的存放路径。

fs.rename(oldPath, newPath, [callback(err)])
  1. oldPath:原路径。
  2. newPath:新路径。
  3. callback:回调函数。传递一个 err 异常参数。
  • 示例
 const fs = require('fs');fs.rename('./css/a.css', './css/index.css', (err) => {if (err) {console.log(err);return;}console.log('更改成功');    // 更改成功})


这里是并没有改变文件路径而只是改变了文件名称,如果想要改变文件路径,只需要将新路径改变为其他文件夹下即可,如 './html/index.css'

8. fs.rmdir: 删除目录


以异步的方式删除文件目录。

fs.rmdir(path, [callback(err)])
  • 示例
 const fs = require('fs');fs.rmdir('./css', (err) => {if (err) {console.log(err);       // 保错:directory not emptyreturn;}console.log('删除目录成功');})

上例报错:directory not empty,说明:当目录中还有其他文件时不能直接删除目录。

9. fs.unlink: 删除文件

删除文件操作。

fs.unlink(path, [callback(err)])
  • 示例
 const fs = require('fs');fs.unlink('./css/index.css', (err) => {if (err) {console.log(err);return;}console.log('删除文件成功');    // 删除文件成功})

10. fs 模块应用


需求:对于如下图所示文件夹 wwwroot,找出 wwwroot 目录下面所有的目录(css、img、js),并放到数组中。

当然,我们首先想到的是利用 for 循环遍历调用,判断是否为目录。实现代码(错误写法)如下所示:

const fs = require('fs');var path = './wwwroot';
var dirArr = [];fs.readdir(path, (err, data) => {if (err) {console.log(err);return;}console.log(data);  // [ 'book.txt', 'css', 'img', 'index.html', 'js' ]for (var i = 0; i < data.length; i++) {fs.stat(path + '/' + data[i], (error, stats) => {if (stats.isDirectory()) {dirArr.push(data[i]);}})}console.log(dirArr);    // []
})

通过打印结果可以看出,这是有问题的。因为 fs.stat 是异步方法,其回调函数内容会放到任务队列中等待执行,当主程序执行栈中任务执行过后,才会被执行。

也就是说,console.log(dirArr) 会被先执行,之后才会执行 fs.stat 的回调函数。

  • 解决方法

为了解决这个问题,可以使用闭包递归执行

fs.readdir(path, (err, data) => {if (err) {console.log(err);return;}console.log(data);   // [ 'book.txt', 'css', 'img', 'index.html', 'js' ](function getDir(i) {if (i == data.length) {console.log(dirArr); // [ 'css', 'img', 'js' ]return;}fs.stat(path + '/' + data[i], (error, stats) => {if (stats.isDirectory()) {dirArr.push(data[i]);}getDir(i + 1);})})(0)
})

但是这段代码看起来还是那么复杂,可行执行较差。除此之外,我们可以使用 Node 中新特性 async await 来解决此方法,这里暂时不先介绍,感兴趣的可参考下文。

二、async 与 await


async/await 是一个期待已久的 JavaScript 特性,让我们更好的理解使用异步函数。它建立在 Promises上,并且与所有现有的基于 Promise 的 API 兼容。

  1. async 是 ES7 中新增内容,对于异步操作的解决方案,它是 Generator 函数的语法糖。
  2. async 和 await 使代码更简洁,语义化。它把异步执行的代码写得像同步代码那样直观,而不是像 Promise 一样有各种 then
  3. async 和 await 保证非阻塞。async 的函数中可以有一个或多个异步操作,一旦遇到 await 就会立即返回一个 pending 状态的 Promise 对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行。
  4. 把异步变同步:在 async 函数内部异步代码就像被同步执行的那样(继发执行)。注意,并不是指它会阻塞主线程一直等待异步调用返回。

下面说一下 async 和 await 的语法。

  • async:声明一个异步函数
 async function name([param]) {statements }

几点说明

  1. 自动将常规函数转换成 Promise,返回值也是一个 Promise 对象
  2. 只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数
  3. 异步函数内部可以使用 await

举个例子

 async function test() {return 'Promise';}console.log(test());        // Promise { 'Promise' }
  • await:等待异步方法执行完成

他几点说明

  1. 放置在 Promise 调用之前,await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。
  2. 若 Promise 正常处理(fulfilled),其回调的 resolve 函数参数作为 await 表达式的值,继续执行 async function
  3. 若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。

举个例子

 async function test() {return 'Promise';}async function main() {var data = await test();console.log(data);}main();           // 打印 Promise
  • 示例

从外部获取异步方法里面的数据。代码如下:

 function test() {return new Promise((resolve, reject) => {setTimeout(() => {var name = '张三';resolve(name);}, 1000);})}async function main() {var data = await test();   // 等待获取 test() 中 Promise 处理结果,也就是等待获取 resolve 返回的参数 value console.log(data);}main();             // 打印 张三
  • 案例改善

可以利用 async/await 对上一节遗留的问题进行改善,问题如下:

需求:对于如下图所示文件夹 wwwroot,找出 wwwroot 目录下面所有的目录(css、img、js),并放到数组中。

上节最后使用的是递归利用闭包解决了异步的问题,这里我们可以使用 async / await 将异步操作变为同步以此解决问题。见下面代码:

const fs = require('fs');async function isDir(path) {return new Promise((resolve, reject) => {// 判断文件还是目录fs.stat(path, (error, stats) => {if (error) {console.log(error);reject(error);}if (stats.isDirectory()) {resolve(true);} else {resolve(false);}})})
}function main() {var path = './wwwroot';var dirArr = [];// 注意 await 应该只能在 async function 内部使用fs.readdir(path, async (err, data) => {if (err) {console.log(err);return;}for (var i = 0; i < data.length; i++) {if (await isDir(path + '/' + data[i])) {    // 利用 await 将异步操作改为同步dirArr.push(data[i]);}}console.log(dirArr);})
}
main();

三、fs 中的流


1. fs.createReadStream

createReadStream 方法往往用于打开大型的文本文件,创建一个读取操作的数据流。所谓大型文本文件,指的是文本文件的体积很大,读取操作的缓存装不下,只能分成几次发送,每次发送会触发一个data 事件,发送结束会触发 end 事件。

 const fs = require('fs');var readStream = fs.createReadStream('./data/input.txt');var count = 0;var str = '';readStream.on('data', (data) => {str += data;count++;})readStream.on('end', () => {console.log(str);console.log(count);})readStream.on('error', (err) => {console.log(err);})

2. fscreateWriteStream()

createWriteStream 方法创建一个写入数据流对象,该对象的 write 方法用于写入数据,end 方法用于结束写入操作。

 var fs = require('fs');var str = '';for (var i = 0; i < 500; i++) {str += '太阳当空照,花儿对我笑\n';}var writeStream = fs.createWriteStream('./data/output.txt');writeStream.write(str);// 标记写入完成writeStream.end();writeStream.on('finish', () => {console.log('写入完成');})

注意:必须利用 writeStream.end() 标记文件结尾后,'finish' 事件才能被执行。

3. 管道流


管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。利用 createWriteStream 方法和 createReadStream 方法配合,可以实现拷贝大型文件。

如下代码,拷贝一个图片 nodejs.png。

const fs = require('fs');var readStream = fs.createReadStream('./nodejs.png');
var writeStream = fs.createWriteStream('./data/nodejs.png');readStream.pipe(writeStream);

Node.js「二」—— fs 模块 / async 与 await相关推荐

  1. Node.js「一」—— Node.js 简介 / Node.js 模块 / 包 与 NPM

    本文为 Node.js 系列笔记第一篇.文章参考:nodejs 教程 -- 大地:<深入浅出 Node.js>:阮一峰 nodejs 博客 文章目录 一.Node 简介 1. 简单介绍 2 ...

  2. 二十六、深入Node.js中的文件系统fs模块

    @Author:Runsen @Date:2020/6/8 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  3. Node.js「三」—— 创建静态 WEB 服务器

    本文为 Node.js 系列笔记第三篇.文章参考:nodejs 教程:<深入浅出 Node.js>:阮一峰 nodejs 博客: Node.js v16.13.0 文档 文章目录 前言 一 ...

  4. Node.js「四」—— 路由 / EJS 模板引擎 / GET 和 POST

    本文为 Node.js 系列笔记第四篇.文章参考:nodejs 教程:<深入浅出 Node.js>:阮一峰 nodejs 博客: Node.js v16.13.0 文档 文章目录 一.路由 ...

  5. Node.js实战13:fs模块奥义!开发一个数据库。

    本文,将使用fs开发一种简单的文件型数据库. 数据库中,记录将采用JSON模式,内容型如: {"key":"a","value":" ...

  6. Node.js基础知识、fs、path、http三大模块、nodejs的模块化、npm与包管理

    文章目录 一.Node.js 简介 二.fs 文件系统模块 读取指定文件中的内容 向指定的文件中写入内容 案例-考试成绩整理 fs 模块 - 路径动态拼接的问题 三.path 路径模块 路径拼接 pa ...

  7. Node.js进程管理之Process模块

    在前面Node.js事件运行机制也有提到,Node.js应用在单个线程运行,但是现在大部分服务器都是多处理器,为了方便使用多个进程,Node.js提供了3个模块.Process模块提供了访问正在运行的 ...

  8. node.js学习笔记5——核心模块1

    node.js学习笔记5--核心模块1 Node.js核心模块主要内容包括:(1)全局对象 (2)常用工具 (3)事件机制 (4)文件系统访问 (5)HTTP服务器与客户端 一: 全局对象 Node. ...

  9. Node.js中使用adm-zip npm模块创建和提取zip文件

    Zip文件是常用的压缩文件格式.大多数开发人员最终使用tarball而不是zip文件.但在某些情况下,您需要使用zip文件,例如将函数上载到AWS Lambda.在本文中,我将演示如何用 adm-zi ...

最新文章

  1. LinkedBlockingQueue 注记
  2. c语言实验七 函数实验报告,C语言实验七函数实验报告.doc
  3. 每日一皮:公司来了个程序员鼓励师...
  4. SpringMVC解决前台传入的数组或集合类型数据
  5. 天平游码读数例题_初二上册物理实验——托盘天平使用的注意事项
  6. 插入排序java_「Java」各类排序算法
  7. java 模拟qq空间登陆_java最新完美实现模拟登录QQ登录QQ空间获取说说
  8. 制作支付页面弹框html,JS实现仿微信支付弹窗功能_蜡烛_前端开发者
  9. spring boot配置mybatis和事务管理
  10. 为何程序C语言不会消亡?程序员学习C会白学吗?
  11. redux 管理你的 react 应用
  12. FFmpeg之mp4提取/h265(二十五)
  13. 毕业设计之时钟模块设计DS1302
  14. linux找不到fastboot驱动下载,fastboot 刷机傻瓜教程
  15. xps15u盘装linux,戴尔xps15系统重装图文教程
  16. 蚂蚁的开放:想办法摸到10米的篮筐 1
  17. Linux shell:echo N > /proc/sys/vm/drop_caches清理缓存
  18. ECSHOP快递单号查询插件圆通V8.2专版
  19. Excel VBA 编程的常用代码
  20. 苹果手机开发微信公众号 禁止分享时遇到了问题

热门文章

  1. Windows Server2012虚拟内存设置
  2. 1.文档数据非结构化
  3. 洛谷 2449 [SDOI2005]矩形
  4. 《Java多线程编程核心技术》读后感(十四)
  5. 浅谈Oracle中物理结构(数据文件等。。。)与逻辑结构(表空间等。。。。。)
  6. AFN的简单二次封装
  7. kafka安装及常用命令
  8. Python-多线程编程
  9. Flutter MaterialApp概述以及主题配置概述
  10. 05 ansible剧本编写