目录
1、文件描述符
2、读取文件
3、stream(流)
3.1 流的类型
1、文件描述符
在您能够与文件系统中的文件进行交互之前,您必须获得一个文件描述符。
文件描述符是对打开文件的引用,是通过使用fs模块提供的open()方法打开文件返回的数字(fd)。此数字(fd)唯一标识操作系统中打开的文件:
const fs = require('fs');
fs.open('/Users/joe/test.txt', 'r', (err, fd) => {// fd 文件描述符
});
fs.open(path, flags, mode, callback)
path 路径
- 标志选项,例如r:可读,r+ 可读写
- mode 默认值:
0o666
(可读写) - fd 文件描述符
通常使用的其他标志有:
标志 | 描述 | 不存在则创建 |
r+ | 此标志打开文件进行读取和写入 | X |
w+ | 此标志打开文件进行读取和写入,并将流定位在文件的开头 | v |
a | 这个标志打开文件进行写入,它还将流定位在文件的末尾 | v |
a+ | 这个标志打开文件进行读写,它还将流定位在文件的末尾 | v |
as | 同步模式下打开追加文件。 | v |
as+ | 在同步模式下打开文件进行读取和追加 | v |
rs+ | 以同步模式打开文件进行阅读 | v |
您也可以使用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/progress模块仅从Node.js v14开始提供。在v14之前,在v10之后,您可以使用require('fs').proness。在v10之前,在v8之后,您可以使用util.proisify将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.prostify的一个示例:
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();
2、读取文件
在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.readFile(path, option, callback)
- path 文件名或文件描述符
- options 包括字符编码,文件系统标志,signal(允许中断正在读的readFile)等。
- callback err:错误,data:读取文件的数据
使用AbortSignal
中止正在进行的请求。如果a 如果请求被中止,则使用AbortError
调用回调:
import { readFile } from 'node:fs';const controller = new AbortController();
const signal = controller.signal;
readFile(fileInfo[0].name, { signal }, (err, buf) => {// ...
});
// 中断请求
controller.abort();
或者,您可以使用同步版本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()这三个函数在返回数据之前都会读取内存中文件的全部内容。
这意味着大文件将对内存消耗和程序执行速度产生重大影响。
在这种情况下,更好的选择是使用流读取文件内容。
3、stream(流)
流是一个抽象接口,用于在Node.js中处理流数据。 node:stream
模块提供实现流接口的API。
Node.js提供了许多流对象。例如,一个 请求到HTTP服务器请求到HTTP服务器请求到HTTP服务器 和process.stdoutprocess.stdoutprocess.stdout 都是流实例。
流可以是可读的、可写的或两者兼有。
要访问node:stream
模块:
const stream = require('stream');
3.1 流的类型
Node.js中有四种基本的流类型:
- Writable:数据可被写入的流(例如, fs.createWriteStream() ).
- Readable:可从中读取数据的流(例如, fs.createReadStream() ).
- Duplex:两者都是的流
Readable
和Writable
(for例如, net.Socket ). - Transform:
Duplex
数据流,可以修改或转换数据 被写入和读取(例如,zlib.createDeflate() ).
通过提供fs
选项,可以覆盖对应的fs
open
、read
和close
的实现。当提供fs
选项时, 需要对read
进行覆盖。如果未提供fd
,则将覆盖 open
也需要。如果autoClose
是true
,还需要覆盖关闭。
import { createReadStream } from 'node:fs';// 从某些字符设备创建流。
const stream = createReadStream('/dev/input/event0');
setTimeout(() => {stream.close(); // 这可能不会关闭流。// 人工标记流尾, 就像基础资源已经// 指示文件结束本身,允许流关闭。// 这不会取消挂起的读取操作,如果有这样的// 操作,进程可能仍然无法成功退出// 直到它完成stream.push(null);stream.read(0);
}, 100);
如果autoClose
为false,则文件描述符不会被关闭,即使 出错了。应用程序负责关闭它并使 确保没有文件描述符泄漏。如果autoClose
设置为true(默认值 行为),则在'error'
或'end'
上,文件描述符将被关闭 自动地。
读取100字节长的文件的最后10个字节的示例:
import { createReadStream } from 'node:fs';createReadStream('sample.txt', { start: 90, end: 99 });