文件系统 fs
读取文件
在 Node.js 中读取文件最简单的方式是使用 fs.readFile() 方法,向其传入文件路径、编码、以及会带上文件数据(以及错误)进行调用的回调函数
js
import fs from 'node:fs'
fs.readFile('README.md', (err, data) => {
if (err) {
console.log('err: ', err)
return
}
console.log('data: ', data)
})传入的路径如果是相对路径则会相对于当前工作目录进行解析
当读取二进制文件时,不传入文件编码时,回调函数的 data 参数将返回一个 Buffer 对象。
js
import fs from 'node:fs'
fs.readFile('README.md', 'utf-8', (err, data) => {
if (err) {
console.log('err: ', err)
return
}
console.log('data: ', data)
})同步读取一个文本文件,如果同步读取文件发生错误,则需要用 try...catch 捕获该错误
js
import fs from 'node:fs'
try {
const data = fs.readFileSync('README.md', 'utf-8')
console.log('data: ', data)
}
catch (err) {
// 出错了
}写入文件
使用 fs.writeFile() 向文件写入内容,如果文件不存在则创建一个新的文件,如果文件已存在则覆盖文件的内容
js
import fs from 'node:fs'
const fileContent = '文件内容'
fs.writeFile('test.txt', fileContent, (err) => {
if (err)
console.log('err: ', err)
else
console.log('写入成功')
})writeFile()的参数依次为文件名、数据和回调函数。如果传入的数据是 String,默认按UTF-8编码写入文本文件,如果传入的参数是Buffer,则写入的是二进制文件。回调函数由于只关心成功与否,因此只需要一个 err 参数。
也可以使用同步的版本 fs.writeFileSync()
js
import fs from 'node:fs'
const fileContent = '同步写入文件内容'
try {
fs.writeFileSync('test.txt', fileContent)
}
catch (error) {
console.log('error: ', error)
}文件属性
每个文件都带有一组详细信息,如:文件大小,创建时间等,可以使用 fs.stat(),它返回一个 Stat 对象,能告诉我们文件或目录的详细信息
js
import fs from 'node:fs'
fs.stat('test.txt', (err, stat) => {
if (err) {
console.log('err: ', err)
return
}
// 文件大小:
console.log(`size: ${stat.size}`)
// 创建时间, Date对象:
console.log(`birth time: ${stat.birthtime}`)
// 修改时间, Date对象:
console.log(`modified time: ${stat.mtime}`)
})判断文件是否存在
js
import fs from 'node:fs'
const util = require('node:util')
const access = util.promisify(fs.access)
async function exists(filePath) {
try {
await access(filePath)
return true
}
catch (err) {
return false
}
}文件权限
js
import { access, constants } from 'node:fs'
const file = 'package.json'
// Check if the file exists in the current directory.
access(file, constants.F_OK, (err) => {
console.log(`${file} ${err ? 'does not exist' : 'exists'}`)
})
// Check if the file is readable.
access(file, constants.R_OK, (err) => {
console.log(`${file} ${err ? 'is not readable' : 'is readable'}`)
})
// Check if the file is writable.
access(file, constants.W_OK, (err) => {
console.log(`${file} ${err ? 'is not writable' : 'is writable'}`)
})
// Check if the file exists in the current directory, and if it is writable.
access(file, constants.F_OK | constants.W_OK, (err) => {
if (err)
console.error(`${file} ${err.code === 'ENOENT' ? 'does not exist' : 'is read-only'}`)
else
console.log(`${file} exists, and it is writable`)
})ensureFile
- fs.stat 判断文件是否存在如果存在则调用 callback
- path.dirname() 获取文件夹路径
- fs.stat 判断文件夹是否存在,如果报错且
err.code === 'ENOENT'则 fs.mkdir() 先创建文件夹,然后 fs.writeFile() 创建文件 - 如果父级不是文件夹,则使用 fs.readdir() 抛出一个错误
js
fs.stat('README.md', (err, stat) => {
if (err) {
console.log('err: ', err)
return
}
if (stat.isFile()) {
// 读取的是文件
}
if (stat.isDirectory()) {
// 读取的是目录
}
})全局文件
globby 通配符快速概述
*: 匹配任意数量的字符,但不包括 /?: 匹配单个字符,但不包括 /**: 匹配任意数量的字符,包括 /,只要它是路径部分中唯一的内容{}: 允许逗号分隔的“或”表达式列表!: 在模式开头将对匹配进行否定
js
const files = await globby(['*.mjs'], {
cwd: path.resolve(process.cwd(), 'oss'),
ignoreFiles: [],
})写入文件
通过 globby 获取项目模板文件
sh
pnpm add globby -Djs
import { globby } from 'globby'
export default class Generator {
async writing() {
const templatePath = join(GENERATOR_DIR, this.inputs.vueVersion)
const templateFiles = await globby([this.inputs.vueVersion], {
cwd: GENERATOR_DIR,
expandDirectories: true,
absolute: true,
dot: true,
})
templateFiles.forEach((filePath) => {
const outputPath = filePath
.replace('.tpl', '')
.replace(templatePath, this.outputDir)
this.copyTpl(filePath, outputPath, this.inputs)
})
}
}编译模板文件
ts
export class Generator {
/**
* 复制模板文件
* @param from 模板文件路径
* @param to 复制到的文件路径
* @param args 模板参数
*/
copyTpl(from: string, to: string, args: Record<string, string>) {
// 复制文件
fs.copySync(from, to)
let content = fs.readFileSync(to, 'utf-8')
// 模板渲染
for (const key in args) {
console.log('args: ', args)
const reg = new RegExp(`<%= ${key} %>`, 'g')
content = content.replace(reg, args[key])
}
fs.writeFileSync(to, content)
const name = basename(to)
}
}