fs 文件操作模块
fs 模块可以实现与硬盘的交互,例如文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的相关操作。
文件操作
写入文件
fs 模块写入文件有两种模式,一种是异步模式,一种是同步模式。
直接写入
通过 fs 模块的 writeFile 方法来实现。
// 异步写入
fs.writeFile('./data.txt', 'data', (err) => {
if (err) {
console.log('写入失败')
return
}
console.log('写入成功')
})
// 同步写入
fs.writeFileSync('./data.txt', 'data')
直接写入会将文件原内容覆盖,一般适用于一次性写入的场景。
追加写入文件
可以通过 writeFile 方法的第三个参数来实现追加写入
// 异步写入
fs.writeFile('./data.txt', '\r\n追加写入的内容1', { flag: 'a' }, (err) => {
if (err) {
console.log('写入失败')
return
}
console.log('写入成功')
})
// 同步写入
fs.writeFileSync('./data.txt', '\r\n追加写入的内容2', { flag: 'a' })
也可以使用 appendFile 方法来实现
// 异步写入
fs.appendFile('./data.txt', '\r\n追加写入的内容1', (err) => {
if (err) {
console.log('写入失败')
return
}
console.log('写入成功')
})
// 同步写入
fs.appendFileSync('./data.txt', '\r\n追加写入的内容2', { flag: 'a' })
流式写入
除了使用 writeFile 方法来实现文件的写入,我们也可以使用流式写入方法来写入文件。
// 1. 创建写入流对象
const ws = fs.createWriteStream('./诗歌.txt')
// 2. 写入内容
ws.write('第一句\r\n')
ws.write('第二句\r\n')
ws.write('第三句\r\n')
ws.write('第四句\r\n')
// 3. 关闭通道(可选)
ws.close()
流式写入类似于追加写入。
流式写入方式适用于大文件写入或者频繁写入的场景,writeFile 适合于写入频率较低的场景。
读取文件
// 异步读取
fs.readFile('./data.txt', (err, data) => {
if (err) {
console.log('读取失败')
return
}
console.log(data.toString())
})
// 同步读取
const data = fs.readFileSync('./data.txt')
console.log(data.toString())
流式读取:分段读取,每次只读取一定字节的数据
// 1. 创建读取流对象
const rs = fs.createReadStream('./data.txt')
// 2. 监听读取事件
rs.on('data', (chunk) => {
// 读取出来的数据
console.log(chunk)
})
// 读取结束事件
rs.on('end', () => {
console.log('end')
})
不管是哪种读取方式,读出来的都是 Buffer 格式的数据。
文件的移动与重命名
// 移动
fs.rename('./data.txt', './data/index.txt', (err) => {
console.log(err)
})
// 重命名
fs.rename('./data.txt', './data2.txt', (err) => {
console.log(err)
})
// 同步操作
fs.renameSync()
文件删除
fs.unlink('./data.txt', (err) => {
console.log(err)
})
fs.rm('./data.txt', (err) => {
console.log(err)
})
// 同步操作
fs.unlinkSync()
fs.rmSync()
文件夹操作
创建文件夹
fs.mkdir('./html', err => {
if (err) {
console.log('创建失败')
return
}
console.log('创建成功')
})
创建嵌套文件夹
fs.mkdir('./html/a/b', { recursive: true }, err => {
if (err) {
console.log('创建失败')
return
}
console.log('创建成功')
})
读取文件夹
fs.readdir('./', (err, data) => {
if (err) {
console.log('读取失败')
return
}
console.log(data)
})
删除文件夹
fs.rmdir('./html', (err) => {
if (err) {
console.log('删除失败')
return
}
console.log('删除成功')
})
path 路径模块
resolve 方法:拼接绝对路径
path.resolve(__dirname, 'index.html')
// 或者
path.resolve(__dirname, './index.html')
// 不允许
path.resolve(__dirname, '/index.html')
http 服务模块
基本使用
使用 http 模块可以启动一个本地的服务
// 导入 http 模块
const http = require('http')
// 创建一个服务对象
const server = http.createServer((request, response) => {
// 获取请求方式
console.log(request.method)
// 获取请求路径
console.log(request.url)
// 获取请求头
console.log(request.headers)
// 设置响应状态码
response.statusCode = 200
// 设置响应头
response.setHeader('content-type', 'text/html;charset=utf-8')
// 自定义响应头
response.setHeader('myHeader', 'abc')
// 设置多个同名的响应头
response.setHeader('test', ['a', 'b', 'c'])
// 设置响应体(返回的数据)
response.write('你好')
response.write('我是')
response.end('kobe') // 必须存在且只能存在一个
})
// 监听端口号启动服务,当浏览器对这个服务发送请求时会触发上面的回调函数
server.listen(8000, () => {
console.log('服务已启动!')
})
使用 node 命令执行以上代码会启动一个本地的服务,此时在浏览器中输入 127.0.0.1:8000,页面上会展示 你好我是kobe
使用 url 模块或 URL 类获取请求路径及参数
当我们在浏览器中输入 http://127.0.0.1:8000/user?name:zs&age=18 向服务发送请求时,我们在服务对象的回调函数中可以获取到请求的路径及参数
// 导入 http 模块
const http = require('http')
// 创建一个服务对象
const server = http.createServer((request, response) => {
// 获取请求路径
console.log(request.url) // /user?name:zs&age=18
response.setHeader('content-type', 'text/html;charset=utf-8')
// 设置响应体
response.end('你好')
})
// 监听端口号启动服务,当浏览器对这个服务发送请求时会触发上面的回调函数
server.listen(8000, () => {
console.log('服务已启动!')
})
但是这个路径是没有经过处理的,我们不能直接进行使用,我们可以使用 url 模块来对其进行处理。
const url = require('url')
const server = http.createServer((request, response) => {
const { pathname, query } = url.parse(request.url, true)
console.log(pathname) // /user
console.log(query) // { name: 'zs', age: '18' }
response.setHeader('content-type', 'text/html;charset=utf-8')
// 设置响应体
response.end('你好')
})
也可以使用 URL 类来处理
const url = require('url')
const server = http.createServer((request, response) => {
const { pathname, query } = new URL(request.url, '127.0.0.1')
console.log(pathname) // /user
console.log(query) //
response.setHeader('content-type', 'text/html;charset=utf-8')
// 设置响应体
response.end('你好')
})
★ 设置静态资源访问
我们可以根据访问的 url 地址来返回不同的静态资源文件。
具体实现思路是,我们将静态资源文件,例如 html 文件,js 文件,css 文件,或者是图片文件都放在某个文件夹下。当浏览器发送请求时我们可以获取到对应的 url 地址,然后拼接上文件夹的路径,通过 fs 模块的文件读取,读取出文件并将其返回。
const url = require('url')
const fs = require('fs')
// 定义 mime 类型
let mimes = {}
const server = http.createServer((request, response) => {
// 获取请求的路径
const { pathname } = new URL(request.url, 'http://127.0.0.1')
// 设置页面根目录
const root = __dirname + '/page'
// 拼接文件读取的路径
let filename
if (pathname === '/') {
// 如果没有写路径,默认读取页面根目录下的 index.html 文件
filename = root + '/index.html'
} else {
filename = root + pathname
}
// 读取文件
fs.readFile(filename, (err, data) => {
// 错误处理
if (err) {
// 设置字符集,解决文件乱码问题
response.setHeader('content-type', 'text/html;charset=utf-8')
// 根据不同错误返回不同状态码及结果
switch (err.code) {
case 'ENOENT':
response.statusCode = 404
response.end('<h1>404 NOT FOUND</h1>')
default:
response.statusCode = 500
response.end('<h1>500</h1>')
}
return
}
// 设置 mime 类型
let ext = path.extname(filename).slice(1)
let type = mimes[ext]
if (type) {
if (ext === 'html') {
response.setHeader('content-type', type + ';charset=utf-8')
} else {
response.setHeader('content-type', type)
}
} else {
response.setHeader('content-type', 'application/octet-stream')
}
response.end(data)
})
})
相对路径与绝对路径
网页中的 url 分为两种:相对路径与绝对路径
绝对路径
绝对路径分为三种
形式:
-
www.bilibili.com/movie 直接向页面发送请求
-
//www.bilibili.com/movie 跟所在页面的协议拼接后再发送请求
-
/movie 跟所在页面的协议 /主机 /端口拼接后再发送请求
相对路径
相对当前页面所在文件进行计算
形式:./login/index.js、./admin/index.js、login/index.js、admin/index.js