什么是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')
/**
* 回调模式
*/
// 第二参数为编码格式,默认为buffer
fs.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()