Node.js操作文件
Node.js操作文件
Node.js文件统计
每个文件都有一组细节,我们可以使用Node.js检查。特别是使用 fs 模块提供的 stat() 方法。
你调用它传递一个文件路径,一旦Node.js 得到文件的详细信息,它就会调用你传递的回调函数,有两个参数:一条错误消息,以及文件统计信息:
const fs = require('fs');
fs.stat('/Users/joe/test.txt', (err, stats) => {
if (err) {
console.error(err);
}
// we have access to the file stats in `stats`
});
Node.js还提供了一个sync方法,该方法会阻塞线程,直到文件状态准备就绪:
const fs = require('fs');
try {
const stats = fs.statSync('/Users/joe/test.txt');
} catch (err) {
console.error(err);
}
文件信息包含在stats变量中。使用统计数据我们可以提取哪些信息?
如果文件是目录或文件,则使用 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
});
如果你愿意,你也可以使用 fs/promises 模块提供的基于promise的 fsPromises.stat() 方法:
const fs = require('fs/promises');
async function example() {
try {
const stats = await fs.stat('/Users/joe/test.txt');
stats.isFile(); // true
stats.isDirectory(); // false
stats.isSymbolicLink(); // false
stats.size; // 1024000 //= 1MB
} catch (err) {
console.log(err);
}
}
example();
您可以在官方文档中阅读更多关于 fs 模块的信息。
Node.js 文件路径
系统中的每个文件都有路径。在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' if run from my home folder
在这种情况下,Node.js将简单地将 /joe.txt 追加到当前工作目录。如果指定第二个参数文件夹, resolve 将使用第一个作为第二个的基础:
path.resolve('tmp', 'joe.txt'); // '/Users/joe/tmp/joe.txt' if run from my home folder
如果第一个参数以斜杠开头,这意味着它是一个绝对路径:
path.resolve('/etc', 'joe.txt'); // '/etc/joe.txt'
path.normalize() 是另一个有用的函数,当它包含相对说明符(如 . 或 .. )或双斜杠时,它将尝试计算实际路径:
path.normalize('/users/joe/..//test.txt'); // '/users/test.txt'
resolve和normalize都不会检查路径是否存在。他们只是根据得到的信息计算出一条路径。
Node.js 中使用文件描述符
在能够与文件系统中的文件进行交互之前,必须获得文件描述符。
文件描述符是对打开的文件的引用,使用 fs 模块提供的 open() 方法打开文件时返回的数字(fd)。此编号( fd )唯一标识操作系统中打开的文件:
const fs = require('fs');
fs.open('/Users/joe/test.txt', 'r', (err, fd) => {
// fd is our file descriptor
});
请注意,我们使用 r 作为 fs.open() 调用的第二个参数。
该标志意味着我们打开文件进行阅读。
您通常使用的其他标志包括:
| 标志 | 描述 | 如果文件不存在则创建文件 |
|---|---|---|
r+ |
此标志打开文件读取 和写入 | ❌ |
w+ |
此标志打开文件读取 和写入 它还将流定位在开始 文件的 | ✅ |
a |
此标志打开文件写入 它还将流定位在结尾 文件的 | ✅ |
a+ |
此标志打开文件读取 和写入 它还将流定位在结尾 文件的 | ✅ |
您也可以使用 fs.openSync 方法打开文件,该方法返回文件描述符,而不是在回调中提供它:
const fs = require('fs');
try {
const fd = fs.openSync('/Users/joe/test.txt', 'r');
} catch (err) {
console.error(err);
}
一旦你得到了文件描述符,无论你选择什么方式,你都可以执行所有需要它的操作,比如调用 fs.close() 和许多其他与文件系统交互的操作。
您也可以使用 fs/promises 模块提供的基于promise的 fsPromises.open 方法打开文件。
fs/promises 模块仅从Node.js v14开始可用。在v14之前,v10之后,您可以使用 require('fs').promises 。在v10之前,在v8之后,你可以使用 util.promisify 将 fs 方法转换为基于promise的方法。
const fs = require('fs/promises');
// Or const fs = require('fs').promises before v14.
async function example() {
let filehandle;
try {
filehandle = await fs.open('/Users/joe/test.txt', 'r');
console.log(filehandle.fd);
console.log(await filehandle.readFile({ encoding: 'utf8' }));
} finally {
if (filehandle) await filehandle.close();
}
}
example();
以下是 util.promisify 的示例:
const fs = require('fs');
const util = require('util');
async function example() {
const open = util.promisify(fs.open);
const fd = await open('/Users/joe/test.txt', 'r');
}
example();
要查看更多关于 fs/promises 模块的详细信息,请查看fs/promises API。
Node.js 读取文件
在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/promises 模块提供的基于promise的 fsPromises.readFile() 方法:
const fs = require('fs/promises');
async function example() {
try {
const data = await fs.readFile('/Users/joe/test.txt', { encoding: 'utf8' });
console.log(data);
} catch (err) {
console.log(err);
}
}
example();
fs.readFile() 、 fs.readFileSync() 和 fsPromises.readFile() 在返回数据之前读取内存中文件的全部内容。
这意味着大文件将对内存消耗和程序执行速度产生重大影响。
在这种情况下,更好的选择是使用流读取文件内容。
Node.js 写入文件
写入文件
在Node.js中写入文件的最简单方法是使用 fs.writeFile() API。
const fs = require('fs');
const content = 'Some content!';
fs.writeFile('/Users/joe/test.txt', content, err => {
if (err) {
console.error(err);
}
// file written successfully
});
同步写入文件
或者,您可以使用同步版本 fs.writeFileSync() :
const fs = require('fs');
const content = 'Some content!';
try {
fs.writeFileSync('/Users/joe/test.txt', content);
// file written successfully
} catch (err) {
console.error(err);
}
您也可以使用 fs/promises 模块提供的基于promise的 fsPromises.writeFile() 方法:
const fs = require('fs/promises');
async function example() {
try {
const content = 'Some content!';
await fs.writeFile('/Users/joe/test.txt', content);
} catch (err) {
console.log(err);
}
}
example();
默认情况下,如果文件的内容已经存在,此API将替换该文件的内容。
可以通过指定标志来修改默认值:
fs.writeFile('/Users/joe/test.txt', content, { flag: 'a+' }, err => {});
您可能会使用的标志有
| 标志 | 描述 | 如果文件不存在则创建文件 |
|---|---|---|
r+ |
此标志打开 reading 和 writing 的文件 | ❌ |
w+ |
此标志为 reading 和 writing 打开文件,并将流定位在文件的 beginning | ✅ |
a |
此标志为 writing 打开文件,并将流定位在文件的 end | ✅ |
a+ |
此标志为 reading 和 writing 打开文件,并将流定位在文件的 end | ✅ |
您可以在fs文档中找到有关标志的更多信息。
向文件追加内容
当您不想用新内容覆盖文件,而是想向文件中添加内容时,向文件追加内容非常方便。
例子
将内容附加到文件末尾的一个方便方法是 fs.appendFile() (及其对应的 fs.appendFileSync() ):
const fs = require('fs');
const content = 'Some content!';
fs.appendFile('file.log', content, err => {
if (err) {
console.error(err);
}
// done!
});
Promises例子
下面是一个 fsPromises.appendFile() 示例:
const fs = require('fs/promises');
async function example() {
try {
const content = 'Some content!';
await fs.appendFile('/Users/joe/test.txt', content);
} catch (err) {
console.log(err);
}
}
example();
Node.js 中使用文件夹
Node.js fs 核心模块提供了许多方便的方法来处理文件夹。
检查文件夹是否存在
使用 fs.access() (及其基于promise-based的 fsPromises.access() 对应项)检查文件夹是否存在,Node.js是否可以使用其权限访问它。
创建新文件夹
使用 fs.mkdir() 或 fs.mkdirSync() 或 fsPromises.mkdir() 创建新文件夹。
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() 或 fsPromises.readdir() 读取目录的内容。
这段代码读取文件夹的内容,包括文件和子文件夹,并返回它们的相对路径:
const fs = require('fs');
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() 或 fsPromises.rename() 重命名文件夹。第一个参数是当前路径,第二个是新路径:
const fs = require('fs');
fs.rename('/Users/joe', '/Users/roger', err => {
if (err) {
console.error(err);
}
// done
});
fs.renameSync() 为同步版本:
const fs = require('fs');
try {
fs.renameSync('/Users/joe', '/Users/roger');
} catch (err) {
console.error(err);
}
fsPromises.rename() 是基于Promise的版本:
const fs = require('fs/promises');
async function example() {
try {
await fs.rename('/Users/joe', '/Users/roger');
} catch (err) {
console.log(err);
}
}
example();
删除文件夹
使用 fs.rmdir() 或 fs.rmdirSync() 或 fsPromises.rmdir() 删除文件夹。
const fs = require('fs');
fs.rmdir(dir, err => {
if (err) {
throw err;
}
console.log(`${dir} is deleted!`);
});
要删除包含内容的文件夹,请使用 fs.rm() 和选项 { recursive: true } 以递归方式删除内容。
{ recursive: true, force: true } 使其在文件夹不存在时忽略异常。
const fs = require('fs');
fs.rm(dir, { recursive: true, force: true }, err => {
if (err) {
throw err;
}
console.log(`${dir} is deleted!`);
});