From c7f3294d0267a19f9d00ad4e95540d086e94a18c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 6 Sep 2021 00:20:45 +0200 Subject: [PATCH] fs: add stream utilities to `FileHandle` PR-URL: https://github.com/nodejs/node/pull/40009 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Backport-PR-URL: https://github.com/nodejs/node/pull/40329 Reviewed-By: Danielle Adams --- doc/api/fs.md | 107 ++++++++++++++++-- lib/internal/fs/promises.js | 40 +++++++ .../test-fs-promises-file-handle-stream.js | 48 ++++++++ 3 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 test/parallel/test-fs-promises-file-handle-stream.js diff --git a/doc/api/fs.md b/doc/api/fs.md index 8f61c8a75cac4e..28d7f2c3e2c570 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -230,6 +230,99 @@ try { } ``` +#### `filehandle.createReadStream([options])` + + +* `options` {Object} + * `encoding` {string} **Default:** `null` + * `autoClose` {boolean} **Default:** `true` + * `emitClose` {boolean} **Default:** `true` + * `start` {integer} + * `end` {integer} **Default:** `Infinity` + * `highWaterMark` {integer} **Default:** `64 * 1024` +* Returns: {fs.ReadStream} + +Unlike the 16 kb default `highWaterMark` for a {stream.Readable}, the stream +returned by this method has a default `highWaterMark` of 64 kb. + +`options` can include `start` and `end` values to read a range of bytes from +the file instead of the entire file. Both `start` and `end` are inclusive and +start counting at 0, allowed values are in the +[0, [`Number.MAX_SAFE_INTEGER`][]] range. If `start` is +omitted or `undefined`, `filehandle.createReadStream()` reads sequentially from +the current file position. The `encoding` can be any one of those accepted by +{Buffer}. + +If the `FileHandle` points to a character device that only supports blocking +reads (such as keyboard or sound card), read operations do not finish until data +is available. This can prevent the process from exiting and the stream from +closing naturally. + +By default, the stream will emit a `'close'` event after it has been +destroyed. Set the `emitClose` option to `false` to change this behavior. + +```mjs +import { open } from 'fs/promises'; + +const fd = await open('/dev/input/event0'); +// Create a stream from some character device. +const stream = fd.createReadStream(); +setTimeout(() => { + stream.close(); // This may not close the stream. + // Artificially marking end-of-stream, as if the underlying resource had + // indicated end-of-file by itself, allows the stream to close. + // This does not cancel pending read operations, and if there is such an + // operation, the process may still not be able to exit successfully + // until it finishes. + stream.push(null); + stream.read(0); +}, 100); +``` + +If `autoClose` is false, then the file descriptor won't be closed, even if +there's an error. It is the application's responsibility to close it and make +sure there's no file descriptor leak. If `autoClose` is set to true (default +behavior), on `'error'` or `'end'` the file descriptor will be closed +automatically. + +An example to read the last 10 bytes of a file which is 100 bytes long: + +```mjs +import { open } from 'fs/promises'; + +const fd = await open('sample.txt'); +fd.createReadStream({ start: 90, end: 99 }); +``` + +#### `filehandle.createWriteStream([options])` + + +* `options` {Object} + * `encoding` {string} **Default:** `'utf8'` + * `autoClose` {boolean} **Default:** `true` + * `emitClose` {boolean} **Default:** `true` + * `start` {integer} +* Returns: {fs.WriteStream} + +`options` may also include a `start` option to allow writing data at some +position past the beginning of the file, allowed values are in the +[0, [`Number.MAX_SAFE_INTEGER`][]] range. Modifying a file rather than replacing +it may require the `flags` `open` option to be set to `r+` rather than the +default `r`. The `encoding` can be any one of those accepted by {Buffer}. + +If `autoClose` is set to true (default behavior) on `'error'` or `'finish'` +the file descriptor will be closed automatically. If `autoClose` is false, +then the file descriptor won't be closed, even if there's an error. +It is the application's responsibility to close it and make sure there's no +file descriptor leak. + +By default, the stream will emit a `'close'` event after it has been +destroyed. Set the `emitClose` option to `false` to change this behavior. + #### `filehandle.datasync()`