ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 章节导航 [TOC] # Node.js-API * `path.basename()`取得一个路径的最后一部分文件名 * `path.normalize()`帮助修正路径 * `path.join()`用于路径拼接(参数为多个路径参数) * `path.resolve()`将一个相对路径解析为绝对路径 * `{basename, dirname, extname}` * `basename` 完整名 * `dirname` 上级路径名 * `extname` 后缀名 * `{parse, format}` * `parse`用于解析当前路径为一个json格式的数据 * `format`相当于格式化json数据为一个字符串 说明:`__dirname`、`__filename`总是返回文件的绝对路径 ​ `process.cwd()`总是返回node命令所在文件夹 #### Buffer 三个要点: * Buffer用于处理二进制数据流 * 实例类似整数数组,大小固定 * C++代码在V8堆外分配物理内存 Buffer常用的方法 * `byteLength`统计buffer所占字节数 * `isBuffer`用来判断目标数据是不是一个Buffer * `concat`合并连接Buffer * `from`将目标数据转换为Buffer * `toString`用来转换Buffer为字符串 #### events * `eventEmitter.on('eventName',callback())`用于注册监听器 * `eventEmitter.emit('eventName')`用于触发事件 ``` const EventEmitter = require('events'); class CustomEvent extends EventEmitter { } const ce = new CustomEvent(); ce.on('eventName',callback); ce.emit('eventName','your msg to eventEmit',....); //有一个通用参数就叫error ce.on('error',fn); //Example ce.on('error',(err, item) => { console.log(err); console.log(item); }); ce.emit('error', new Error('出错了'), Date().now); ``` 针对事件只需要响应一次: ~~~ ce.once('test', ()=> { console.log(test); }); 复制代码 ~~~ 针对事件需要移除的话: ~~~ ce.removeListener('eventName',fn); //or ce.removeAllListeners('test'); 复制代码 ~~~ ## fs 首先需要注意的就是Node.js的设计模型就是错误优先的模式 ``` fs.readFile('fileUrl','utf8',(err,data) => { if(err) throw err; console.log(data) }) ``` stat( ) 查看文件详细信息 ``` const fs = require('fs'); fs.stat('filerUrl',(err,data) => { if(err){ throw err; } console.log(data) }) ``` rename( ) 更改文件名 ``` fs.rename('./text.tex','hahah.ttx'); ``` unlink( ) 删除文件 ``` fs.unlink('fileName',err => err); ``` readdir( ) 读取文件夹 mkdir( )创建文件夹 rmdir( ) 删除文件夹 watch( )监视文件或目录变化 ``` fs.watch('fileUrl', { recursive:true //是否监视子文件夹 }, (eventType, fileName) => { console.log(eventType, fileName); }) ``` * `readStream()`读取流 ~~~ const rs = fs.createReadStream('urlPath'); rs.pipe(process.stdout);//导出文件到控制台 复制代码 ~~~ * `writeStream()`写入流 * `pipe()`管道,导通流文件 ~~~ const ws = fscreateWriteStream('urlPath'); ws.write('some content'); ws.end(); ws.on('finish',()=>{ console.log('done!!!'); }); ~~~ ## 静态资源服务器 #### `http`模块 ~~~ const http = require('http'); const chalk = require('chalk'); const hostname = '127.0.0.1'; const port = '3000'; const server = http.createServe((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World'); }); server.listen(port, hostname, () => { const addr = `Server running at http://${hostname}:${port}/`; console.log(`${chalk.green(addr)}`); }) ~~~ * `supervisor`监视文件模块 * `hotnode`热启动模块 # 额外项目案例 ~~~ // 1. 引入 http 模块 var http = require("http"); // 2. 用 http 模块创建服务 /** * req 获取 url 信息 (request) * res 浏览器返回响应信息 (response) */ http.createServer(function (req, res) { // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('<h1 style="text-align:center">Hello NodeJS</h1>'); // 结束响应 res.end(); }).listen(3000); // 监听的端口 复制代码 ~~~  那么,上面代码,我们要怎么用呢?  **首先**,将上面的代码复制粘贴到 `01_http.js` 中。  **然后**,启动 VS Code 终端:`Ctrl + ~`。  **接着**,输入 `node 01_http.js` 并回车。  **最后**,打开 `localhost:3000`: 1. **首先**,我们需要先开启仙人模式。哦,不是,是 HTTP 模式。我们都知道,像 PHP 这类老牌子的后端语言,需要 Apache 或者 Nginx 开启 HTTP 服务。然而我们的 Node 不需要: ~~~ var http = require("http"); 复制代码 ~~~ 2. **然后**,开启 HTTP 服务,并设置开启的端口: ~~~ /** * req 获取 url 信息 (request) * res 浏览器返回响应信息 (response) */ http.createServer(function (req, res) { // ... 步骤 3 代码 }).listen(3000); // 监听的端口 复制代码 ~~~ 3. **接着**,我们设置 HTTP 头部,并往页面打印值,最后结束响应: ~~~ // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('<h1 style="text-align:center">Hello NodeJS</h1>'); // 结束响应 res.end(); ~~~ ~~~ // 1. 引入 url 模块 var url = require("url"); // 2. 引入 http 模块 var http = require("http"); // 3. 用 http 模块创建服务 /** * req 获取 url 信息 (request) * res 浏览器返回响应信息 (response) */ http.createServer(function (req, res) { // 4. 获取服务器请求 /** * 访问地址是:http://localhost:3000/?userName=jsliang&userAge=23 * 如果你执行 console.log(req.url),它将执行两次,分别返回下面的信息: * / ?userName=jsliang&userAge=23 * / /favicon.ico * 这里为了防止重复执行,所以排除 req.url == /favicon.ico 的情况 */ if(req.url != "/favicon.ico") { // 5. 使用 url 的 parse 方法 /** * parse 方法需要两个参数: * 第一个参数是地址 * 第二个参数是 true 的话表示把 get 传值转换成对象 */ var result = url.parse(req.url, true); console.log(result); /** * Url { * protocol: null, * slashes: null, * auth: null, * host: null, * port: null, * hostname: null, * hash: null, * search: '?userName=jsliang&userAge=23', * query: { userName: 'jsliang', userAge: '23' }, * pathname: '/', * path: '/?userName=jsliang&userAge=23', * href: '/?userName=jsliang&userAge=23' } */ console.log(result.query.userName); // jsliang console.log(result.query.userAge); // 23 } // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('<h1 style="text-align:center">Hello NodeJS</h1>'); // 结束响应 res.end(); }).listen(3000); 复制代码 ~~~  在上面的代码中:  **首先**,我们引入该章节的主角 `url` 模块: ~~~ // 1. 引入 url 模块 var url = require("url"); 复制代码 ~~~  **然后**,我们引入 `http` 模块: ~~~ // 2. 引入 http 模块 var http = require("http"); 复制代码 ~~~  **接着**,我们创建 `http` 模块,因为 `url` 的监听,需要 `http` 模块的开启: ~~~ // 3. 用 http 模块创建服务 /** * req 获取 url 信息 (request) * res 浏览器返回响应信息 (response) */ http.createServer(function (req, res) { // ... 第 4 步、第 5 步代码 // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('<h1 style="text-align:center">Hello NodeJS</h1>'); // 结束响应 res.end(); }).listen(3000); ~~~ ## URL模块 URL 模块是什么呢? 我们在控制台(终端)开启 Node 模式,并打印出`url`来看一下: 好家伙,它有`Url`、`parse`、`resolve`、`resolveObject`、`format`、`URL`、`URLSearchParams`、`domainToASCII`、`domainToUnicode`这么多模块。 那么,这些模块都有什么用呢? ### 引入代码url.js ``` // 1. 引入 url 模块 var url = require("url"); // 2. 引入 http 模块 var http = require("http"); // 3. 用 http 模块创建服务 /** * req 获取 url 信息 (request) * res 浏览器返回响应信息 (response) */ http.createServer(function (req, res) { // 4. 获取服务器请求 /** * 访问地址是:http://localhost:3000/?userName=jsliang&userAge=23 * 如果你执行 console.log(req.url),它将执行两次,分别返回下面的信息: * / ?userName=jsliang&userAge=23 * / /favicon.ico * 这里为了防止重复执行,所以排除 req.url == /favicon.ico 的情况 */ if(req.url != "/favicon.ico") { // 5. 使用 url 的 parse 方法 /** * parse 方法需要两个参数: * 第一个参数是地址 * 第二个参数是 true 的话表示把 get 传值转换成对象 */ var result = url.parse(req.url, true); console.log(result); /** * Url { * protocol: null, * slashes: null, * auth: null, * host: null, * port: null, * hostname: null, * hash: null, * search: '?userName=jsliang&userAge=23', * query: { userName: 'jsliang', userAge: '23' }, * pathname: '/', * path: '/?userName=jsliang&userAge=23', * href: '/?userName=jsliang&userAge=23' } */ console.log(result.query.userName); // jsliang console.log(result.query.userAge); // 23 } // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('<h1 style="text-align:center">Hello NodeJS</h1>'); // 结束响应 res.end(); }).listen(3000); ``` 在上面的代码中:  **首先**,我们引入该章节的主角 `url` 模块: ~~~ // 1. 引入 url 模块 var url = require("url"); 复制代码 ~~~  **然后**,我们引入 `http` 模块: ~~~ // 2. 引入 http 模块 var http = require("http"); 复制代码 ~~~  **接着**,我们创建 `http` 模块,因为 `url` 的监听,需要 `http` 模块的开启: ~~~ // 3. 用 http 模块创建服务 /** * req 获取 url 信息 (request) * res 浏览器返回响应信息 (response) */ http.createServer(function (req, res) { // ... 第 4 步、第 5 步代码 // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('<h1 style="text-align:center">Hello NodeJS</h1>'); // 结束响应 res.end(); }).listen(3000); ~~~ ``` // 4. 获取服务器请求 /** * 访问地址是:http://localhost:3000/?userName=jsliang&userAge=23 * 如果你执行 console.log(req.url),它将执行两次,分别返回下面的信息: * / ?userName=jsliang&userAge=23 * / /favicon.ico * 这里为了防止重复执行,所以排除 req.url == /favicon.ico 的情况 */ if(req.url != "/favicon.ico") { // 5. 使用 url 的 parse 方法 /** * parse 方法需要两个参数: * 第一个参数是地址 * 第二个参数是 true 的话表示把 get 传值转换成对象 */ var result = url.parse(req.url, true); console.log(result); /** * Url { * protocol: null, * slashes: null, * auth: null, * host: null, * port: null, * hostname: null, * hash: null, * search: '?userName=jsliang&userAge=23', * query: { userName: 'jsliang', userAge: '23' }, * pathname: '/', * path: '/?userName=jsliang&userAge=23', * href: '/?userName=jsliang&userAge=23' } */ console.log(result.query.userName); // jsliang console.log(result.query.userAge); // 23 } ``` 从中,我们可以看出,我们可以通过 `query`,获取到我们想要的路径字段。  当然,上面只讲解了 `parse` 的用法,我们可以将上面代码中 `if` 语句里面的代码全部清空。然后,输入下面的内容,去学习 `url` 模块更多的内容: 1. url 模块所有内容: ~~~ console.log(url); /** * Console: { Url: [Function: Url], parse: [Function: urlParse], // 获取地址信息 resolve: [Function: urlResolve], // 追加或者替换地址 resolveObject: [Function: urlResolveObject], format: [Function: urlFormat], // 逆向 parse,根据地址信息获取原 url 信息 URL: [Function: URL], URLSearchParams: [Function: URLSearchParams], domainToASCII: [Function: domainToASCII], domainToUnicode: [Function: domainToUnicode] } */ 复制代码 ~~~ 2. parse 如何使用 ~~~ console.log(url.parse("http://www.baidu.com")); /** * Console: Url { protocol: 'http:', slashes: true, auth: null, host: 'www.baidu.com', port: null, hostname: 'www.baidu.com', hash: null, search: null, query: null, pathname: '/', path: '/', href: 'http://www.baidu.com/' } */ 复制代码 ~~~ 3. parse 带参数: ~~~ console.log(url.parse("http://www.baidu.com/new?name=zhangsan")); /** * Console: Url { protocol: 'http:', slashes: true, auth: null, host: 'www.baidu.com', port: null, hostname: 'www.baidu.com', hash: null, search: '?name=zhangsan', query: 'name=zhangsan', pathname: '/new', path: '/new?name=zhangsan', href: 'http://www.baidu.com/new?name=zhangsan' } */ 复制代码 ~~~ 4. `format` 的使用: ~~~ console.log(url.format({ protocol: 'http:', slashes: true, auth: null, host: 'www.baidu.com', port: null, hostname: 'www.baidu.com', hash: null, search: '?name=zhangsan', query: 'name=zhangsan', pathname: '/new', path: '/new?name=zhangsan', href: 'http://www.baidu.com/new?name=zhangsan' })) // Console: // http://www.baidu.com/new?name=zhangsan 复制代码 ~~~ 5. `resolve` 的使用: ~~~ console.log(url.resolve("http://www.baidu.com/123", "222")); // Console: // http://www.baidu.com/222 ~~~ ## NPM * `npm -v`:查看 npm 版本。 * `npm list`:查看当前目录下都安装了哪些 npm 包。 * `npm info 模块`:查看该模块的版本及内容。 * `npm i 模块@版本号`:安装该模块的指定版本。  在平时使用 npm 安装包的过程中,你可能需要知道一些 npm 基本知识: * `i`/`install`:安装。使用 `install` 或者它的简写 `i`,都表明你想要下载这个包。 * `uninstall`:卸载。如果你发现这个模块你已经不使用了,那么可以通过 `uninstall` 卸载它。 * `g`:全局安装。表明这个包将安装到你的计算机中,你可以在计算机任何一个位置使用它。 * `--save`/`-S`:通过该种方式安装的包的名称及版本号会出现在 `package.json` 中的 `dependencies` 中。`dependencies` 是需要发布在生成环境的。例如:`ElementUI` 是部署后还需要的,所以通过 `-S` 形式来安装。 * `--save-dev`/`-D`:通过该种方式安装的包的名称及版本号会出现在 `package.json` 中的 `devDependencies` 中。`devDependencies` 只在开发环境使用。例如:`gulp` 只是用来压缩代码、打包的工具,程序运行时并不需要,所以通过 `-D` 形式来安装。  例子: * `cnpm i webpack-cli -D` * `npm install element-ui -S`  那么,这么多的 npm 包,我们通过什么管理呢?  答案是 `package.json`。  如果我们需要创建 `package.json`,那么我们只需要在指定的包管理目录(例如 `node_modules`)中通过以下命名进行生成: * `npm init`:按步骤创建 `package.json`。 * `npm init --yes`:快速创建 `package.json`  当然,因为国内网络环境的原因,有些时候通过 npm 下载包,可能会很慢或者直接卡断,这时候就要安装淘宝的 npm 镜像:cnpm * `npm install -g cnpm --registry=https://registry.npm.taobao.org` ## fs文件管理 * `fs.stat` 检测是文件还是目录 * `fs.mkdir` 创建目录 * `fs.writeFile` 创建写入文件 * `fs.appendFile` 追加文件 * `fs.readFile` 读取文件 * `fs.readdir` 读取目录 * `fs.rename` 重命名 * `fs.rmdir` 删除目录 * `fs.unlink` 删除文件 我们尝试通过 `fs.mkdir` 创建目录: > 05\_fs.js ~~~ // 2. fs.mkdir let fs = require('fs'); /** * 接收参数 * path - 将创建的目录路径 * mode - 目录权限(读写权限),默认 0777 * callback - 回调,传递异常参数 err */ fs.mkdir('css', (err) => { if(err) { console.log(err); return false; } else { console.log("创建目录成功!"); // Console:创建目录成功! } }) 复制代码 ~~~  通过 `node 05_fs.js`,我们发现目录中多了一个 `css` 文件夹。  **那么**,有创建就有删除,创建的目录如何删除呢?这里讲解下 `fs.rmdir`: > 05\_fs.js ~~~ // 8. fs.rmdir let fs = require('fs'); /** * 接收参数 * path - 将创建的目录路径 * mode - 目录权限(读写权限),默认 0777 * callback - 回调,传递异常参数 err */ fs.rmdir('css', (err) => { if(err) { console.log(err); return false; } else { console.log("创建目录成功!"); // Console:创建目录成功! } }) 复制代码 ~~~  通过 `node 05_fs.js`,我们发现目录中的 `css` 文件夹被删除了。  **接着**,我们通过 `fs.writeFile` 来创建写入文件: > 05\_fs.js ~~~ // 3. fs.writeFile let fs = require('fs'); /** * filename (String) 文件名称 * data (String | Buffer) 将要写入的内容,可以是字符串或者 buffer 数据。 * · encoding (String) 可选。默认 'utf-8',当 data 是 buffer 时,该值应该为 ignored。 * · mode (Number) 文件读写权限,默认 438。 * · flag (String) 默认值 'w'。 * callback { Function } 回调,传递一个异常参数 err。 */ fs.writeFile('index.js', 'Hello jsliang', (err) => { if(err) { console.log(err); return false; } else { console.log('写入成功!'); } }) 复制代码 ~~~  值得注意的是,这样的写入,是清空原文件中的所有数据,然后添加 `Hello jsliang` 这句话。即:存在即覆盖,不存在即创建。  有创建就有删除,感兴趣的可以使用 `fs.unlink` 进行文件的删除,再次不做过多讲解。  **既然**,上面的是覆盖文件,那么有没有追加文件呢?有的,使用 `fs.appendFile` 吧: > 05\_fs.js ~~~ // 4. fs.appendFile let fs = require('fs'); fs.appendFile('index.js', '这段文本是要追加的内容', (err) => { if(err) { console.log(err); return false; } else { console.log("追加成功"); } }) 复制代码 ~~~  这样,我们就成功往里面追加了一段话,从而使 `index.js` 变成了: > index.js ~~~ Hello jsliang这段文本是要追加的内容 复制代码 ~~~  **在上面**,我们已经做了:新增、修改、删除操作。那么小伙伴一定很熟悉下一步骤是做什么了: * `fs.readFile` 读取文件 * `fs.readdir` 读取目录 > 05\_fs.js ~~~ let fs = require('fs'); // 5. fs.readFile fs.readFile('index.js', (err, data) => { if(err) { console.log(err); return false; } else { console.log("读取文件成功!"); console.log(data); // Console: // 读取文件成功! // <Buffer 48 65 6c 6c 6f 20 6a 73 6c 69 61 6e 67 e8 bf 99 e6 ae b5 e6 96 87 e6 9c ac e6 98 af e8 a6 81 e8 bf bd e5 8a a0 e7 9a 84 e5 86 85 e5 ae b9> } }) // 6. fs.readdir 读取目录 fs.readdir('node_modules', (err, data) => { if(err) { console.log(err); return false; } else { console.log("读取目录成功!"); console.log(data); // Console: // 读取目录成功! // [ '03_tool-multiply.js', 'jsliang-module' ] } }) 复制代码 ~~~ ### rename重命名 ~~~ let fs = require('fs'); // 7. fs.rename 重命名 fs.rename('index.js', 'jsliang.js', (err) => { if(err) { console.log(err); return false; } else { console.log("重命名成功!"); } }) 复制代码 ~~~  当然,如果 `fs.rename` 还有更劲爆的功能:剪切 > _fs.js ~~~ let fs = require('fs'); // 7. fs.rename 重命名 fs.rename('jsliang.js', 'node_modules/jsliang.js', (err) => { if(err) { console.log(err); return false; } else { console.log("剪切成功!"); } }) ~~~