1、文件描述符
在您能够与文件系统中的文件进行交互之前,您必须获得一个文件描述符。
文件描述符是对打开文件的引用,是通过使用fs模块提供的open()方法打开文件返回的数字(fd)。此数字(fd)唯一标识操作系统中打开的文件:
1. const fs = require('fs'); 2. fs.open('/Users/joe/test.txt', 'r', (err, fd) => { 3. // fd 文件描述符 4. });
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方法打开文件,该方法返回文件描述符,而不是在回调中提供:
1. const fs = require('fs'); 2. try { 3. const fd = fs.openSync('/Users/joe/test.txt', 'r'); 4. } catch (err) { 5. console.error(err); 6. }
一旦您获得了文件描述符,无论您选择什么方式,您都可以执行所有需要它的操作,比如调用fs.close()和许多其他与文件系统交互的操作。
您也可以使用fs/promises模块提供的基于promise的fsPromises.open方法打开文件。
fs/progress模块仅从Node.js v14开始提供。在v14之前,在v10之后,您可以使用require('fs').proness。在v10之前,在v8之后,您可以使用util.proisify将fs方法转换为基于promise的方法。
1. const fs = require('fs/promises'); 2. // Or const fs = require('fs').promises before v14. 3. async function example() { 4. let filehandle; 5. try { 6. filehandle = await fs.open('/Users/joe/test.txt', 'r'); 7. console.log(filehandle.fd); 8. console.log(await filehandle.readFile({ encoding: 'utf8' })); 9. } finally { 10. if (filehandle) await filehandle.close(); 11. } 12. } 13. example();
以下是util.prostify的一个示例:
1. const fs = require('fs'); 2. const util = require('util'); 3. async function example() { 4. const open = util.promisify(fs.open); 5. const fd = await open('/Users/joe/test.txt', 'r'); 6. } 7. example();
2、读取文件
在Node.js中读取文件的最简单方法是使用fs.readFile()方法,向其传递文件路径、编码和回调函数,该函数将与文件数据(以及错误)一起调用:
1. const fs = require('fs'); 2. fs.readFile('/Users/joe/test.txt', 'utf8', (err, data) => { 3. if (err) { 4. console.error(err); 5. return; 6. } 7. console.log(data); 8. });
fs.readFile(path, option, callback)
- path 文件名或文件描述符
- options 包括字符编码,文件系统标志,signal(允许中断正在读的readFile)等。
- callback err:错误,data:读取文件的数据
使用AbortSignal
中止正在进行的请求。如果a 如果请求被中止,则使用AbortError
调用回调:
1. import { readFile } from 'node:fs'; 2. 3. const controller = new AbortController(); 4. const signal = controller.signal; 5. readFile(fileInfo[0].name, { signal }, (err, buf) => { 6. // ... 7. }); 8. // 中断请求 9. controller.abort();
或者,您可以使用同步版本fs.readFileSync():
1. const fs = require('fs'); 2. try { 3. const data = fs.readFileSync('/Users/joe/test.txt', 'utf8'); 4. console.log(data); 5. } catch (err) { 6. console.error(err); 7. }
您还可以使用fs/promises模块提供的基于promise的fsPromises.readFile()方法:
1. const fs = require('fs/promises'); 2. async function example() { 3. try { 4. const data = await fs.readFile('/Users/joe/test.txt', { encoding: 'utf8' }); 5. console.log(data); 6. } catch (err) { 7. console.log(err); 8. } 9. } 10. 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
,还需要覆盖关闭。
1. import { createReadStream } from 'node:fs'; 2. 3. // 从某些字符设备创建流。 4. const stream = createReadStream('/dev/input/event0'); 5. setTimeout(() => { 6. stream.close(); // 这可能不会关闭流。 7. // 人工标记流尾, 就像基础资源已经 8. // 指示文件结束本身,允许流关闭。 9. // 这不会取消挂起的读取操作,如果有这样的 10. // 操作,进程可能仍然无法成功退出 11. // 直到它完成 12. stream.push(null); 13. stream.read(0); 14. }, 100);
如果autoClose
为false,则文件描述符不会被关闭,即使 出错了。应用程序负责关闭它并使 确保没有文件描述符泄漏。如果autoClose
设置为true(默认值 行为),则在'error'
或'end'
上,文件描述符将被关闭 自动地。
读取100字节长的文件的最后10个字节的示例:
1. import { createReadStream } from 'node:fs'; 2. 3. createReadStream('sample.txt', { start: 90, end: 99 });