一.在Nodejs使用文件描述符
在与位于文件系统中的文件进行交互之前,需要先获取文件的描述符。
文件描述符是使用 fs
模块提供的 open()
方法打开文件后返回的:
const fs = require('fs')
fs.open('/Users/joe/test.txt', 'r', (err, fd) => {
//fd 是文件描述符。
})
注意,将 r
作为 fs.open()
调用的第二个参数。
该标志意味着打开文件用于读取。
r+
打开文件用于读写。w+
打开文件用于读写,将流定位到文件的开头。如果文件不存在则创建文件。a
打开文件用于写入,将流定位到文件的末尾。如果文件不存在则创建文件。a+
打开文件用于读写,将流定位到文件的末尾。如果文件不存在则创建文件。
const fs = require('fs')
try {
const fd = fs.openSync('/Users/joe/test.txt', 'r')
} catch (err) {
console.error(err)
}
一旦获得文件描述符,就可以以任何方式执行所有需要它的操作,例如调用 fs.open()
以及许多与文件系统交互的其他操作。
二.Nodejs文件属性
每个文件都带有一组详细信息,可以使用 Node.js 进行检查。
具体地说,使用 fs
模块提供的 stat()
方法。
调用时传入文件的路径,一旦 Node.js 获得文件的详细信息,则会调用传入的回调函数,并带上两个参数:错误消息和文件属性:
const fs = require('fs')
fs.stat('/Users/joe/test.txt', (err, stats) => {
if (err) {
console.error(err)
return
}
//可以访问 `stats` 中的文件属性
})
Node.js 也提供了同步的方法,该方法会阻塞线程,直到文件属性准备就绪为止:
const fs = require('fs')
try {
const stats = fs.statSync('/Users/joe/test.txt')
} catch (err) {
console.error(err)
}
文件的信息包含在属性变量中。 可以通过属性提取哪些信息?
很多,包括:
- 使用
stats.isFile()
和stats.isDirectory()
判断文件是否目录或文件。 - 使用
stats.isSymbolicLink()
判断文件是否符号链接。 - 使用
stats.size
获取文件的大小(以字节为单位)。
还有其他一些高级的方法,但是在日常编程中会使用的大部分是这些。
const fs = require('fs')
fs.stat('/Users/joe/test.txt', (err, stats) => {
if (err) {
console.error(err)
return
}
stats.isFile() //true
stats.isDirectory() //false
stats.isSymbolicLink() //false
stats.size //1024000 //= 1MB
})
三.Nodejs文件路径
系统中的每个文件都有路径。
在 Linux 和 macOS 上,路径可能类似于:
/users/joe/file.txt
在 Windows 上则有所不同,具有类似以下的结构:
C:\users\joe\file.txt
当在应用程序中使用路径时需要注意,因为必须考虑到这种差异。
可以使用以下方式将此模块引入到文件中:
const path = require('path')
现在可以开始使用其方法。
从路径中获取信息
给定一个路径,可以使用以下方法从其中提取信息:
dirname
: 获取文件的父文件夹。basename
: 获取文件名部分。extname
: 获取文件的扩展名。
例如:
const notes = '/users/joe/notes.txt'
path.dirname(notes) // /users/joe
path.basename(notes) // notes.txt
path.extname(notes) // .txt
可以通过为 basename
指定第二个参数来获取不带扩展名的文件名:
path.basename(notes, path.extname(notes)) //notes
使用路径
可以使用 path.join()
连接路径的两个或多个片段:
const name = 'joe'
path.join('/', 'users', name, 'notes.txt') //'/users/joe/notes.txt'
可以使用 path.resolve()
获得相对路径的绝对路径计算:
path.resolve('joe.txt') //'/Users/joe/joe.txt' 如果从主文件夹运行。
在此示例中,Node.js 只是简单地将 /joe.txt
附加到当前工作目录。 如果指定第二个文件夹参数,则 resolve
会使用第一个作为第二个的基础:
path.resolve('tmp', 'joe.txt') //'/Users/joe/tmp/joe.txt' 如果从主文件夹运行。
如果第一个参数以斜杠开头,则表示它是绝对路径:
path.resolve('/etc', 'joe.txt') //'/etc/joe.txt'
path.normalize()
是另一个有用的函数,当包含诸如 .
、..
或双斜杠之类的相对说明符时,其会尝试计算实际的路径:
path.normalize('/users/joe/..//test.txt') ///users/test.txt
解析和规范化都不会检查路径是否存在。 其只是根据获得的信息来计算路径。
四.Nodejs读取文件
在 Node.js 中读取文件最简单的方式是使用 fs.readFile()
方法,向其传入文件路径、编码、以及会带上文件数据(以及错误)进行调用的回调函数:
const fs = require('fs')
fs.readFile('/Users/joe/test.txt', 'utf8' , (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
})
另外,也可以使用同步的版本 fs.readFileSync()
:
const fs = require('fs')
try {
const data = fs.readFileSync('/Users/joe/test.txt', 'utf8')
console.log(data)
} catch (err) {
console.error(err)
}
fs.readFile()
和 fs.readFileSync()
都会在返回数据之前将文件的全部内容读取到内存中。
这意味着大文件会对内存的消耗和程序执行的速度产生重大的影响。
在这种情况下,更好的选择是使用流来读取文件的内容。
五.Nodejs写入文件
在 Node.js 中写入文件最简单的方式是使用 fs.writeFile()
API。
例如:
const fs = require('fs')
const content = '一些内容'
fs.writeFile('/Users/joe/test.txt', content, err => {
if (err) {
console.error(err)
return
}
//文件写入成功。
})
另外,也可以使用同步的版本 fs.writeFileSync()
:
const fs = require('fs')
const content = '一些内容'
try {
const data = fs.writeFileSync('/Users/joe/test.txt', content)
//文件写入成功。
} catch (err) {
console.error(err)
}
默认情况下,此 API 会替换文件的内容(如果文件已经存在)。
可以通过指定标志来修改默认的行为:
fs.writeFile('/Users/joe/test.txt', content, { flag: 'a+' }, err => {})
可能会使用的标志有:
r+
打开文件用于读写。w+
打开文件用于读写,将流定位到文件的开头。如果文件不存在则创建文件。a
打开文件用于写入,将流定位到文件的末尾。如果文件不存在则创建文件。a+
打开文件用于读写,将流定位到文件的末尾。如果文件不存在则创建文件。
(可以在 http://nodejs.cn/api/fs.html#fs_file_system_flags 中查看更多标志)
追加到文件
将内容追加到文件末尾的便捷方法是 fs.appendFile()
(及其对应的 fs.appendFileSync()
):
const content = '一些内容'
fs.appendFile('file.log', content, err => {
if (err) {
console.error(err)
return
}
//完成!
})
使用流
所有这些方法都是在将全部内容写入文件之后才会将控制权返回给程序(在异步的版本中,这意味着执行回调)。
在这种情况下,更好的选择是使用流写入文件的内容。
六.Nodejs使用文件夹
Node.js 的 fs
核心模块提供了许多便捷的方法用于处理文件夹。
检查文件夹是否存在
使用 fs.access()
检查文件夹是否存在以及 Node.js 是否具有访问权限。
创建新的文件夹
使用 fs.mkdir()
或 fs.mkdirSync()
可以创建新的文件夹。
const fs = require('fs')
const folderName = '/Users/joe/test'
try {
if (!fs.existsSync(folderName)) {
fs.mkdirSync(folderName)
}
} catch (err) {
console.error(err)
}
读取目录的内容
使用 fs.readdir()
或 fs.readdirSync()
可以读取目录的内容。
这段代码会读取文件夹的内容(全部的文件和子文件夹),并返回它们的相对路径:
const fs = require('fs')
const path = require('path')
const folderPath = '/Users/joe'
fs.readdirSync(folderPath)
可以获取完整的路径:
fs.readdirSync(folderPath).map(fileName => {
return path.join(folderPath, fileName)
})
也可以过滤结果以仅返回文件(排除文件夹):
const isFile = fileName => {
return fs.lstatSync(fileName).isFile()
}
fs.readdirSync(folderPath).map(fileName => {
return path.join(folderPath, fileName)
})
.filter(isFile)
重命名文件夹
使用 fs.rename()
或 fs.renameSync()
可以重命名文件夹。 第一个参数是当前的路径,第二个参数是新的路径:
const fs = require('fs')
fs.rename('/Users/joe', '/Users/roger', err => {
if (err) {
console.error(err)
return
}
//完成
})
fs.renameSync()
是同步的版本:
const fs = require('fs')
try {
fs.renameSync('/Users/joe', '/Users/roger')
} catch (err) {
console.error(err)
}
删除文件夹
使用 fs.rmdir()
或 fs.rmdirSync()
可以删除文件夹。
删除包含内容的文件夹可能会更复杂。
在这种情况下,最好安装 fs-extra
模块,该模块非常受欢迎且维护良好。 它是 fs
模块的直接替代品,在其之上提供了更多的功能。
在此示例中,需要的是 remove()
方法。
使用以下命令安装:
npm install fs-extra
并像这样使用它:
const fs = require('fs-extra')
const folder = '/Users/joe'
fs.remove(folder, err => {
console.error(err)
})
也可以与 promise 一起使用:
fs.remove(folder)
.then(() => {
//完成
})
.catch(err => {
console.error(err)
})
或使用 async/await:
async function removeFolder(folder) {
try {
await fs.remove(folder)
//完成
} catch (err) {
console.error(err)
}
}
const folder = '/Users/joe'
removeFolder(folder)