Webcourse/10-Node.js和数据库/05-Node.js内置模块:fs文件模块.md
2020-06-18 14:35:38 +08:00

391 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Node.js 的官方API文档
- Node.js 的API文档英文 <https://nodejs.org/docs/latest-v8.x/api/index.html>
- Node.js 的API文档中文<http://nodejs.cn/api/>
关于 Node.js 的内置模块和常见API可以看官方文档
查阅文档时稳定指数如下
- 红色废弃
- 橙色实验表示当前版本可用其他版本不确定也许不向下兼容建议不要在生产环境中使用该特性
- 绿色稳定 npm 生态系统的兼容性是最高的优先级
## Node.js 中模块的分类
Node.js 应用由模块组成采用 CommonJS 模块规范Node.js中的模块分为三种
- 内置模块
- 第三方模块
- 自定义模块
下面简单介绍一下
### 1内置模块
```js
const process = require('process');
const path = require('path');
console.log(process.version);
console.log(path.resolve('../'));
```
require方法用于加载模块
常见的内置模块包括
- FS文件系统模块
- path路径模块
- OS操作系统相关
- net网络相关
- http
- ...
你可能会有疑问Node.js 这么牛吗还能直接和操作系统做交互
带着这个疑问我们不妨简单看看 Node.js 的源码 os 模块举例
- 打开os模块的源码<https://github.com/nodejs/node/blob/master/lib/os.js>,翻到最底部,找到 `cpus`这个方法
- 进而找到 `getCPUs()`
- internalBinding('os')通过 internalBinding 可以调用系统底层的方法internalBinding 主要是 JS 虚拟机在做的事情
- `internalBinding('os')` 的实现 <https://github.com/nodejs/node/blob/master/src/node_os.cc> 里,里面都是 C++ 的代码。比如有一个`getCPUs`方法。
现在你知道了JS本身是没有能力获取底层系统资源的这一切都是 JS虚拟机在和底层做交互然后通过 JS 的表现形式暴露给应用层
另外还有很多库是直接使用C/++编写的通过编译之后再提供给 JS 应用层调用或者直接提供给 Node.js层使用
**所有的编程语言底层都会回归C/C++**甚至是汇编语言
### 2require 加载第三方包的机制
```js
const express = require('express');
```
require 加载第三方包的机制
1第三方包安装好后这个包一般会存放在当前项目的 node_modules 文件夹中我们找到这个包的 package.json 文件并且找到里面的main属性对应的入口模块这个入口模块就是这个包的入口文件
2如果第三方包中没有找到package.json文件或者package.json文件中没有main属性则默认加载第三方包中的index.js文件
3如果在 node_modules 文件夹中没有找到这个包或者以上所有情况都没有找到则会向上一级父级目录下查找node_modules文件夹查找规则如上一致
4如果一直找到该模块的磁盘根路径都没有找到则会报错can not find module xxx
### 3自定义模块module
每个文件就是一个模块有自己的作用域在一个文件里面定义的变量函数都是私有的对其他文件不可见
举例
```
var example = require('./example.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
```
## 读取文件
今天这篇文章重点讲一下 Node 内置模块中的 **fs文件处理模块**
在使用文件模块之前记得先导入
```js
// 导入文件模块
const fs = require('fs');
```
fs 的英文全称是 File Systemfs 模块提供了很多 api 方法我们首先应该学习的方法是**文件读取**
Node中文件读取的方式主要有以下几种
### 异步读取文件 fs.readFile()
语法格式
```js
fs.readFile(file[, options], callback(error, data))
```
代码举例
```javascript
const fs = require('fs');
fs.readFile('hello.txt', 'utf8', (err, data) => {
if (err) {
// 失败
console.log(err)
} else {
// 成功
console.log('异步读取数据:' + data2)
}
});
```
如果需要嵌套读取多个文件可以用 promise 或者 async ... await 进行封装代码举例如下
### promise 封装 fs.readFile()
```js
const fs = require('fs');
function fsRead(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, { flag: 'r', encoding: "utf-8" }, (err, data) => {
if (err) {
//失败执行的内容
reject(err)
} else {
//成功执行的内容
resolve(data)
}
})
})
}
var promise1 = fsRead('hello1.txt')
promise1.then(res1 => {
console.log(res1);
return fsRead('hello2.txt');
}).then(res2 => {
console.log(res2);
return fsRead('hello3.txt');
}).then(res3 => {
console.log(res);
})
```
### async ... await 封装 fs.readFile()
这个写法更为简洁推荐
```js
var fs = require('fs');
function fsRead(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, { flag: 'r', encoding: "utf-8" }, (err, data) => {
if (err) {
//失败执行的内容
reject(err)
} else {
//成功执行的内容
resolve(data)
}
})
})
}
async function ReadList() {
var res1 = await fsRead('hello1.txt');
var res2 = await fsRead('hello2.txt');
var res3 = await fsRead('hello3.txt');
}
// 执行方法
ReadList();
```
### 同步读取文件 fs.readFileSync()
语法格式
```js
fs.readFileSync(file[, options])
```
代码举例
```javascript
const fs = require('fs');
try {
const data = fs.readFileSync('hello.txt', 'utf8');
console.log(data);
} catch(e) {
// 文件不存在,或者权限错误
throw e;
}
```
### Node.js 中的同步和异步的区别
fs模块对文件的几乎所有操作都有同步和异步两种形式例如readFile() readFileSync()
区别
- 同步调用会阻塞代码的执行异步则不会
- 异步调用会将 读取任务 下达到任务队列直到任务执行完成才会回调
- 异常处理方面同步必须使用 try catch 方式异步可以通过回调函数的第一个参数重要
## 写入文件
语法格式
```js
fs.write(fd, string[, position[, encoding]], callback)
```
async ... await 封装
```js
let fs = require('fs')
function writeFs(path, content) {
return new Promise(function (resolve, reject) {
fs.writeFile(path, content, { flag: "a", encoding: "utf-8" }, function (err) {
if (err) {
//console.log("写入内容出错")
reject(err)
} else {
resolve(err)
//console.log("写入内容成功")
}
})
})
}
async function writeList() {
await writeFs('1.html', "<h1>qianguyihao</h1>");
await writeFs('2.html', "<h1>hello world</h1>");
await writeFs('3.html', "<h1>永不止步</h1>");
}
writeList()
```
## 删除文件
语法格式
```js
fs.unlink(path, callback)
```
参数说明
- path文件路径
- callback回调函数
代码举例
```js
fs.unlink('path/file.txt', (err) => {
if (err) throw err;
console.log('文件删除成功');
});
```
备注`fs.unlink()` 不能用于删除目录 如果要删除目录可以使用 `fs.rmdir()`
## Buffer
通过 Buffer 开辟的内存空间都是连续的内存空间所以效率比较高
代码举例1
```js
// 将字符串转成 buffer 对象
const str = 'qianguyihao';
let buffer = Buffer.from(str);
console.log(buffer); // 输出16进制编码
console.log(buffer.toString()); // 输出字符串qianguyihao
```
代码举例2
```js
// 从内存中开辟一个新的缓冲区
let buffer = Buffer.alloc(20);
buffer[0] = 'a';
console.log(buffer);
```
## 读取目录
语法格式
```js
fs.mkdir(path[, options], callback)
```
参数说明
- path文件路径
- options参数可以是
- recursive是否以递归的方式创建目录默认为 false
- mode设置目录权限默认为 0777
代码举例
```js
var fs = require("fs");
console.log("查看 /tmp 目录");
fs.readdir("/tmp/",function(err, files){
if (err) {
return console.error(err);
}
files.forEach( function (file){
console.log( file );
});
});
```
其他的还有暂略
- 删除目录
- 输入输出