什么是I/O
就是input 与 output 输入与输出设备
对外部设备的输入输出都是I/O
什么是外部设备
出啦cpu跟内存之外都是外部设备,我们的程序只跟cpu跟内存打交道
向外部设备写入数据就是input 从外部设备中读取数据就是output 对外部设备的输入与输出就称为I/O
外部设备举例:磁盘,网卡,显卡,打印机
注意: IO的速度往往低于内存和cpu的交互速度
cpu只跟内存打交道,cpu是不会直接去读取硬盘的
想要跟IO设备就行交互就需要把IO设备的东西写入内存
fs模块
文件系统的基础操作
注意:fs模块内的api 分为同步模式与异步模式:
同步模式的api名字结尾都是Sync 同步模式的api会导致 js运行阻塞及其影响性能 通常,在程序启动时运行有限次数即可,例如程序启动前读取某个配置文件,当缺失这个配置文件程序不运行
异步模式又分为:回调模式与promise模式(promise模式是在node12的版本之后开启的,但由于之前的用的回调模式,故将回调模式的api做成 promise版本的api,与回调模式的api名字一样,功能也一样,promise模式的api通过fs.promises.api的名字)
读取文件: fs.readFile
示例
const fs = require('fs');const path = require('path');const p = path.resolve(__dirname, './1/1.txt')/*** 回调模式*/// 第二参数为编码格式,默认为bufferfs.readFile(p, 'utf8', (err, data) => {console.log(err, 'err');console.log(data, 'data');});/*** Promise*/async function test() {const content = await fs.promises.readFile(p, "utf-8");console.log(content);}test()
向文件写入内容:fs.writeFile
示例
const fs = require('fs');const path = require('path');const p = path.resolve(__dirname, './1/1.txt');/*** 回调* 当写入为空时会创建文件* 默认编码格式为utf-8* 模式是覆盖写入* 可以通过flag进行修改* flag参考地址http://nodejs.cn/api/fs.html#fs_file_system_flags* 文本追加写入的flag值为 a 也就是append* 如果文件不存在会新建文件,但是并不会新建文件夹**/fs.writeFile(p, ' this is write text', {flag: 'a'}, (err) => {if(err) {console.log(err, 'err')}else {console.log('写入成功')}})/*** Promise*/async function test() {// await fs.promises.writeFile(p, "阿斯顿发发放到发", {// flag: "a" //追加内容// });const buffer = Buffer.from("abcde", "utf-8");await fs.promises.writeFile(p, buffer);console.log("写入成功");}test();
获取文件或目录信息:fs.stat
示例:
const path = require('path');const fs = require('fs');const filename = path.resolve(__dirname, './1/1.jpg');/*** 回调模式*/fs.stat(filename, (err, stats) => {if (err) {console.log(err, 'err');} else {console.log(stats.isDirectory(), 'stats');}});// 打印出来的结果 文件 与文件夹都可打印出信息 文件夹size 为0// Stats {// dev: 2286631492,// mode: 33206,// nlink: 1,// uid: 0,// gid: 0,// rdev: 0,// blksize: 4096,// ino: 844424933052844,// size: 69, 占用的字节 文件夹为的值是0// blocks: 0,// atimeMs: 1627710102357.6472,// mtimeMs: 1627710034670.8054,// ctimeMs: 1627710034670.8054,// birthtimeMs: 1627708383846.325,// atime: 2021-07-31T05:41:42.358Z, 上次访问的时间// mtime: 2021-07-31T05:40:34.671Z, 上次文件内容被修改的时间// ctime: 2021-07-31T05:40:34.671Z, 上次文件状态被修改的时间// birthtime: 2021-07-31T05:13:03.846Z 文件被创建的时间// }/*** promise*/async function test() {const stat = await fs.promises.stat(filename);console.log(stat);console.log('是否是目录', stat.isDirectory());console.log('是否是文件', stat.isFile());}test();
获取目录中的文件和子目录:fs.readdir
示例
const path = require('path')const fs = require('fs')const p =path.resolve(__dirname)// 只能查看当前目录,并不会查看子目录里的文件// 目录也是特殊的文件, 目录的size为0// async function print() {// const result = await fs.promises.readdir(p);// console.log(result);// }// print()fs.readdir(p, (err, files) => {if(err) {console.log(err)} else {console.log(files, 'chenggong')}})
创建目录:fs.mkdir
示例
const path = require('path')const fs = require('fs')const p = path.resolve(__dirname, './4')/*** 异步模式* 创建多个文件当有一个文件找不到就会报错* 例如创建./5/1 目录5没有 目录1没有 会直接报错因为目录5找不到*/// async function print() {// const res = await fs.promises.mkdir(p)// console.log(res, 'res')// }// print()/*** 回调模式*/fs.mkdir(p, (err) => {console.log(err)})
判断文件或目录是否存在:fs.exists
fs.exists 已经废弃
使用fs.stat判断文件目录是否存在
const path = require('path')const fs = require('fs')const dirName = path.resolve(__dirname, './4')async function stats(dirName) {try {/**获取文件或目录的信息 */await fs.promises.stat(dirName)return true;} catch (err) {//ENOENT; 是找不到的意思,也就是不存在if(err.code === 'ENOENT') {return false}throw err;}}async function exists () {const res = await stats(dirName)console.log(res)}exists()
案例
手动复制文件
技术点:
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()
<a name="tZRXk"></a>### 读取一个目录中的所有子目录和文件<a name="GNQZL"></a>#### 技术点:- 查看文件的详细信息- 从文件路径中提取信息- 判断是否为文件- 查看目录下的子文件- 读取文件内容- Promise 的应用 如Promise.all 以及何时不使用then 而直接返回结果- 类的静态属性的使用<a name="u61o3"></a>#### 代码:```javascript/*** 给我一个文件路径* 先将这个文件进行解析 获取文件相关信息* 将其信息弄成对象保存起来* 看它还有没有子目录* 有子目录将每个子目录进行解析,获取相关文件信息*/const fs = require('fs');const path = require('path');class File {constructor(fileName= '', name = '', ext = '', isFile = false, size = '', createTime = '', updateTime = '') {this.fileName = fileName; // 当前文件路径this.name = name; // 文件名this.ext = ext; // 后缀名this.isFile = isFile; // 是否是一个文件this.size = size; // 文件大小this.createTime = createTime; // 创建时间this.updateTime = updateTime; // 修改时间}/*** 得到目录所有子文件对象如果是文件,则返回空数组* 如果有子文件 获取子文件的信息 当获取到所有子文件信息返回*/async getChilefiles() {if (this.isFile) return [];const dirName = path.resolve(this.fileName)let readDIrFiles = await fs.promises.readdir(dirName);readDIrFiles = readDIrFiles.map(ele => {const fileName = path.resolve(this.fileName, ele);return File.getFile(fileName)})return Promise.all(readDIrFiles)}/*** 读取文件内容, 如果是目录则返回null*/async readFiles(buffer = false) {if(!this.isFile) return null;if(buffer) {return await fs.promises.readFile(this.fileName)} else {return await fs.promises.readFile(this.fileName, 'utf-8')}}/*** 静态方法 获取获取文件或目录信息* @param {*} dirName* @returns*/static async getFile(dirName) {const name = path.basename(dirName); // 获取文件名const ext = path.extname(name); //后缀const stats = await fs.promises.stat(dirName);const size = stats.size; // 大小const createTime = stats.birthtime; // 创建时间const updateTime = stats.mtime; // 修改时间const isFile = stats.isFile() //是否为文件return new File(dirName, name, ext, isFile, size, createTime, updateTime);}}/*** 获取文件信息* @param {*} dirName* @returns* 获取文件信息* 判断是否有子目录*/async function geStats(dirName) {const stats = await File.getFile(dirName);return await stats.getChilefiles();}/*** 主入口*/async function print() {const dirName = path.resolve(__dirname);const result = await geStats(dirName)console.log(result)}print()
