什么是I/O

就是input 与 output 输入与输出设备
对外部设备的输入输出都是I/O

什么是外部设备

出啦cpu跟内存之外都是外部设备,我们的程序只跟cpu跟内存打交道
向外部设备写入数据就是input 从外部设备中读取数据就是output 对外部设备的输入与输出就称为I/O
外部设备举例:磁盘,网卡,显卡,打印机
注意: IO的速度往往低于内存和cpu的交互速度
cpu只跟内存打交道,cpu是不会直接去读取硬盘的
想要跟IO设备就行交互就需要把IO设备的东西写入内存

fs模块

通过fs模块,这个模块可以跟操作系统的文件系统打交道

文件系统的基础操作

注意:fs模块内的api 分为同步模式与异步模式:
同步模式的api名字结尾都是Sync 同步模式的api会导致 js运行阻塞及其影响性能 通常,在程序启动时运行有限次数即可,例如程序启动前读取某个配置文件,当缺失这个配置文件程序不运行
异步模式又分为:回调模式与promise模式(promise模式是在node12的版本之后开启的,但由于之前的用的回调模式,故将回调模式的api做成 promise版本的api,与回调模式的api名字一样,功能也一样,promise模式的api通过fs.promises.api的名字)

读取文件: fs.readFile

示例

  1. const fs = require('fs');
  2. const path = require('path');
  3. const p = path.resolve(__dirname, './1/1.txt')
  4. /**
  5. * 回调模式
  6. */
  7. // 第二参数为编码格式,默认为buffer
  8. fs.readFile(p, 'utf8', (err, data) => {
  9. console.log(err, 'err');
  10. console.log(data, 'data');
  11. });
  12. /**
  13. * Promise
  14. */
  15. async function test() {
  16. const content = await fs.promises.readFile(p, "utf-8");
  17. console.log(content);
  18. }
  19. test()

向文件写入内容:fs.writeFile

示例

  1. const fs = require('fs');
  2. const path = require('path');
  3. const p = path.resolve(__dirname, './1/1.txt');
  4. /**
  5. * 回调
  6. * 当写入为空时会创建文件
  7. * 默认编码格式为utf-8
  8. * 模式是覆盖写入
  9. * 可以通过flag进行修改
  10. * flag参考地址http://nodejs.cn/api/fs.html#fs_file_system_flags
  11. * 文本追加写入的flag值为 a 也就是append
  12. * 如果文件不存在会新建文件,但是并不会新建文件夹
  13. *
  14. */
  15. fs.writeFile(p, ' this is write text', {
  16. flag: 'a'
  17. }, (err) => {
  18. if(err) {
  19. console.log(err, 'err')
  20. }else {
  21. console.log('写入成功')
  22. }
  23. })
  24. /**
  25. * Promise
  26. */
  27. async function test() {
  28. // await fs.promises.writeFile(p, "阿斯顿发发放到发", {
  29. // flag: "a" //追加内容
  30. // });
  31. const buffer = Buffer.from("abcde", "utf-8");
  32. await fs.promises.writeFile(p, buffer);
  33. console.log("写入成功");
  34. }
  35. test();

获取文件或目录信息:fs.stat

示例:

  1. const path = require('path');
  2. const fs = require('fs');
  3. const filename = path.resolve(__dirname, './1/1.jpg');
  4. /**
  5. * 回调模式
  6. */
  7. fs.stat(filename, (err, stats) => {
  8. if (err) {
  9. console.log(err, 'err');
  10. } else {
  11. console.log(stats.isDirectory(), 'stats');
  12. }
  13. });
  14. // 打印出来的结果 文件 与文件夹都可打印出信息 文件夹size 为0
  15. // Stats {
  16. // dev: 2286631492,
  17. // mode: 33206,
  18. // nlink: 1,
  19. // uid: 0,
  20. // gid: 0,
  21. // rdev: 0,
  22. // blksize: 4096,
  23. // ino: 844424933052844,
  24. // size: 69, 占用的字节 文件夹为的值是0
  25. // blocks: 0,
  26. // atimeMs: 1627710102357.6472,
  27. // mtimeMs: 1627710034670.8054,
  28. // ctimeMs: 1627710034670.8054,
  29. // birthtimeMs: 1627708383846.325,
  30. // atime: 2021-07-31T05:41:42.358Z, 上次访问的时间
  31. // mtime: 2021-07-31T05:40:34.671Z, 上次文件内容被修改的时间
  32. // ctime: 2021-07-31T05:40:34.671Z, 上次文件状态被修改的时间
  33. // birthtime: 2021-07-31T05:13:03.846Z 文件被创建的时间
  34. // }
  35. /**
  36. * promise
  37. */
  38. async function test() {
  39. const stat = await fs.promises.stat(filename);
  40. console.log(stat);
  41. console.log('是否是目录', stat.isDirectory());
  42. console.log('是否是文件', stat.isFile());
  43. }
  44. test();

获取目录中的文件和子目录:fs.readdir

示例

  1. const path = require('path')
  2. const fs = require('fs')
  3. const p =path.resolve(__dirname)
  4. // 只能查看当前目录,并不会查看子目录里的文件
  5. // 目录也是特殊的文件, 目录的size为0
  6. // async function print() {
  7. // const result = await fs.promises.readdir(p);
  8. // console.log(result);
  9. // }
  10. // print()
  11. fs.readdir(p, (err, files) => {
  12. if(err) {
  13. console.log(err)
  14. } else {
  15. console.log(files, 'chenggong')
  16. }
  17. })

创建目录:fs.mkdir

示例

  1. const path = require('path')
  2. const fs = require('fs')
  3. const p = path.resolve(__dirname, './4')
  4. /**
  5. * 异步模式
  6. * 创建多个文件当有一个文件找不到就会报错
  7. * 例如创建./5/1 目录5没有 目录1没有 会直接报错因为目录5找不到
  8. */
  9. // async function print() {
  10. // const res = await fs.promises.mkdir(p)
  11. // console.log(res, 'res')
  12. // }
  13. // print()
  14. /**
  15. * 回调模式
  16. */
  17. fs.mkdir(p, (err) => {
  18. console.log(err)
  19. })

判断文件或目录是否存在:fs.exists

fs.exists 已经废弃
image.png
使用fs.stat判断文件目录是否存在

  1. const path = require('path')
  2. const fs = require('fs')
  3. const dirName = path.resolve(__dirname, './4')
  4. async function stats(dirName) {
  5. try {
  6. /**获取文件或目录的信息 */
  7. await fs.promises.stat(dirName)
  8. return true;
  9. } catch (err) {
  10. //ENOENT; 是找不到的意思,也就是不存在
  11. if(err.code === 'ENOENT') {
  12. return false
  13. }
  14. throw err;
  15. }
  16. }
  17. async function exists () {
  18. const res = await stats(dirName)
  19. console.log(res)
  20. }
  21. exists()

案例

手动复制文件

技术点:

  • 文件的读取与写入

    代码:

    ```javascript const path = require(‘path’); const fs = require(‘fs’);

async function test () { const fromFilename = path.resolve(dirname, ‘./1/1.jpg’); const readImg = await fs.promises.readFile(fromFilename); const writePath = path.resolve(dirname, ‘./1/1_copy.jpg’); await fs.promises.writeFile(writePath, readImg); console.log(“copy success!”); } test()

  1. <a name="tZRXk"></a>
  2. ### 读取一个目录中的所有子目录和文件
  3. <a name="GNQZL"></a>
  4. #### 技术点:
  5. - 查看文件的详细信息
  6. - 从文件路径中提取信息
  7. - 判断是否为文件
  8. - 查看目录下的子文件
  9. - 读取文件内容
  10. - Promise 的应用 如Promise.all 以及何时不使用then 而直接返回结果
  11. - 类的静态属性的使用
  12. <a name="u61o3"></a>
  13. #### 代码:
  14. ```javascript
  15. /**
  16. * 给我一个文件路径
  17. * 先将这个文件进行解析 获取文件相关信息
  18. * 将其信息弄成对象保存起来
  19. * 看它还有没有子目录
  20. * 有子目录将每个子目录进行解析,获取相关文件信息
  21. */
  22. const fs = require('fs');
  23. const path = require('path');
  24. class File {
  25. constructor(fileName= '', name = '', ext = '', isFile = false, size = '', createTime = '', updateTime = '') {
  26. this.fileName = fileName; // 当前文件路径
  27. this.name = name; // 文件名
  28. this.ext = ext; // 后缀名
  29. this.isFile = isFile; // 是否是一个文件
  30. this.size = size; // 文件大小
  31. this.createTime = createTime; // 创建时间
  32. this.updateTime = updateTime; // 修改时间
  33. }
  34. /**
  35. * 得到目录所有子文件对象如果是文件,则返回空数组
  36. * 如果有子文件 获取子文件的信息 当获取到所有子文件信息返回
  37. */
  38. async getChilefiles() {
  39. if (this.isFile) return [];
  40. const dirName = path.resolve(this.fileName)
  41. let readDIrFiles = await fs.promises.readdir(dirName);
  42. readDIrFiles = readDIrFiles.map(ele => {
  43. const fileName = path.resolve(this.fileName, ele);
  44. return File.getFile(fileName)
  45. })
  46. return Promise.all(readDIrFiles)
  47. }
  48. /**
  49. * 读取文件内容, 如果是目录则返回null
  50. */
  51. async readFiles(buffer = false) {
  52. if(!this.isFile) return null;
  53. if(buffer) {
  54. return await fs.promises.readFile(this.fileName)
  55. } else {
  56. return await fs.promises.readFile(this.fileName, 'utf-8')
  57. }
  58. }
  59. /**
  60. * 静态方法 获取获取文件或目录信息
  61. * @param {*} dirName
  62. * @returns
  63. */
  64. static async getFile(dirName) {
  65. const name = path.basename(dirName); // 获取文件名
  66. const ext = path.extname(name); //后缀
  67. const stats = await fs.promises.stat(dirName);
  68. const size = stats.size; // 大小
  69. const createTime = stats.birthtime; // 创建时间
  70. const updateTime = stats.mtime; // 修改时间
  71. const isFile = stats.isFile() //是否为文件
  72. return new File(dirName, name, ext, isFile, size, createTime, updateTime);
  73. }
  74. }
  75. /**
  76. * 获取文件信息
  77. * @param {*} dirName
  78. * @returns
  79. * 获取文件信息
  80. * 判断是否有子目录
  81. */
  82. async function geStats(dirName) {
  83. const stats = await File.getFile(dirName);
  84. return await stats.getChilefiles();
  85. }
  86. /**
  87. * 主入口
  88. */
  89. async function print() {
  90. const dirName = path.resolve(__dirname);
  91. const result = await geStats(dirName)
  92. console.log(result)
  93. }
  94. print()