mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
fs: move fs.promises API to fs/promises
PR-URL: https://github.com/nodejs/node/pull/18777 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
2620358624
commit
513d939720
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs/promises');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [20e4],
|
||||
@ -10,11 +10,11 @@ const bench = common.createBenchmark(main, {
|
||||
|
||||
async function run(n, statType) {
|
||||
const arg = statType === 'fstat' ?
|
||||
await fs.promises.open(__filename, 'r') : __filename;
|
||||
await fsPromises.open(__filename, 'r') : __filename;
|
||||
let remaining = n;
|
||||
bench.start();
|
||||
while (remaining-- > 0)
|
||||
await fs.promises[statType](arg);
|
||||
await fsPromises[statType](arg);
|
||||
bench.end(n);
|
||||
|
||||
if (typeof arg.close === 'function')
|
||||
|
124
doc/api/fs.md
124
doc/api/fs.md
@ -3231,9 +3231,9 @@ Synchronous versions of [`fs.write()`][]. Returns the number of bytes written.
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
The `fs.promises` API provides an alternative set of asynchronous file system
|
||||
The `fs/promises` API provides an alternative set of asynchronous file system
|
||||
methods that return `Promise` objects rather than using callbacks. The
|
||||
API is accessible via `fs.promises`.
|
||||
API is accessible via `require('fs/promises)`.
|
||||
|
||||
### class: FileHandle
|
||||
<!-- YAML
|
||||
@ -3247,11 +3247,11 @@ in that, if the `FileHandle` is not explicitly closed using the
|
||||
and will emit a process warning, thereby helping to prevent memory leaks.
|
||||
|
||||
Instances of the `FileHandle` object are created internally by the
|
||||
`fs.promises.open()` method.
|
||||
`fsPromises.open()` method.
|
||||
|
||||
Unlike callback-based such as `fs.fstat()`, `fs.fchown()`, `fs.fchmod()`,
|
||||
`fs.ftruncate()`, `fs.read()`, and `fs.write()`, operations -- all of which
|
||||
use a simple numeric file descriptor, all `fs.promises.*` variations use the
|
||||
use a simple numeric file descriptor, all `fsPromises.*` variations use the
|
||||
`FileHandle` class in order to help protect against accidental leaking of
|
||||
unclosed file descriptors after a `Promise` is resolved or rejected.
|
||||
|
||||
@ -3317,7 +3317,7 @@ Closes the file descriptor.
|
||||
async function openAndClose() {
|
||||
let filehandle;
|
||||
try {
|
||||
filehandle = await fs.promises.open('thefile.txt', 'r');
|
||||
filehandle = await fsPromises.open('thefile.txt', 'r');
|
||||
} finally {
|
||||
if (filehandle !== undefined)
|
||||
await filehandle.close();
|
||||
@ -3378,7 +3378,7 @@ object. Otherwise, the data will be a string.
|
||||
|
||||
If `options` is a string, then it specifies the encoding.
|
||||
|
||||
When the `path` is a directory, the behavior of `fs.promises.readFile()` is
|
||||
When the `path` is a directory, the behavior of `fsPromises.readFile()` is
|
||||
platform-specific. On macOS, Linux, and Windows, the promise will be rejected
|
||||
with an error. On FreeBSD, a representation of the directory's contents will be
|
||||
returned.
|
||||
@ -3422,8 +3422,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
|
||||
// Prints: Node.js
|
||||
|
||||
async function doTruncate() {
|
||||
const fd = await fs.promises.open('temp.txt', 'r+');
|
||||
await fs.promises.ftruncate(fd, 4);
|
||||
const fd = await fsPromises.open('temp.txt', 'r+');
|
||||
await fsPromises.ftruncate(fd, 4);
|
||||
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints: Node
|
||||
}
|
||||
|
||||
@ -3438,8 +3438,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
|
||||
// Prints: Node.js
|
||||
|
||||
async function doTruncate() {
|
||||
const fd = await fs.promises.open('temp.txt', 'r+');
|
||||
await fs.promises.ftruncate(fd, 10);
|
||||
const fd = await fsPromises.open('temp.txt', 'r+');
|
||||
await fsPromises.ftruncate(fd, 10);
|
||||
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints Node.js\0\0\0
|
||||
}
|
||||
|
||||
@ -3518,7 +3518,7 @@ The `FileHandle` has to support writing.
|
||||
It is unsafe to use `filehandle.writeFile()` multiple times on the same file
|
||||
without waiting for the `Promise` to be resolved (or rejected).
|
||||
|
||||
### fs.promises.access(path[, mode])
|
||||
### fsPromises.access(path[, mode])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3547,18 +3547,18 @@ with an `Error` object. The following example checks if the file
|
||||
`/etc/passwd` can be read and written by the current process.
|
||||
|
||||
```js
|
||||
fs.promises.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK)
|
||||
fsPromises.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK)
|
||||
.then(() => console.log('can access'))
|
||||
.catch(() => console.error('cannot access'));
|
||||
```
|
||||
|
||||
Using `fs.promises.access()` to check for the accessibility of a file before
|
||||
calling `fs.promises.open()` is not recommended. Doing so introduces a race
|
||||
Using `fsPromises.access()` to check for the accessibility of a file before
|
||||
calling `fsPromises.open()` is not recommended. Doing so introduces a race
|
||||
condition, since other processes may change the file's state between the two
|
||||
calls. Instead, user code should open/read/write the file directly and handle
|
||||
the error raised if the file is not accessible.
|
||||
|
||||
### fs.promises.appendFile(file, data[, options])
|
||||
### fsPromises.appendFile(file, data[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3578,9 +3578,9 @@ resolved with no arguments upon success.
|
||||
If `options` is a string, then it specifies the encoding.
|
||||
|
||||
The `file` may be specified as a `FileHandle` that has been opened
|
||||
for appending (using `fs.promises.open()`).
|
||||
for appending (using `fsPromises.open()`).
|
||||
|
||||
### fs.promises.chmod(path, mode)
|
||||
### fsPromises.chmod(path, mode)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3592,7 +3592,7 @@ added: REPLACEME
|
||||
Changes the permissions of a file then resolves the `Promise` with no
|
||||
arguments upon succces.
|
||||
|
||||
### fs.promises.chown(path, uid, gid)
|
||||
### fsPromises.chown(path, uid, gid)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3605,7 +3605,7 @@ added: REPLACEME
|
||||
Changes the ownership of a file then resolves the `Promise` with no arguments
|
||||
upon success.
|
||||
|
||||
### fs.promises.copyFile(src, dest[, flags])
|
||||
### fsPromises.copyFile(src, dest[, flags])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3632,7 +3632,7 @@ Example:
|
||||
const fs = require('fs');
|
||||
|
||||
// destination.txt will be created or overwritten by default.
|
||||
fs.promises.copyFile('source.txt', 'destination.txt')
|
||||
fsPromises.copyFile('source.txt', 'destination.txt')
|
||||
.then(() => console.log('source.txt was copied to destination.txt'))
|
||||
.catch(() => console.log('The file could not be copied'));
|
||||
```
|
||||
@ -3645,12 +3645,12 @@ const fs = require('fs');
|
||||
const { COPYFILE_EXCL } = fs.constants;
|
||||
|
||||
// By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
|
||||
fs.promises.copyFile('source.txt', 'destination.txt', COPYFILE_EXCL)
|
||||
fsPromises.copyFile('source.txt', 'destination.txt', COPYFILE_EXCL)
|
||||
.then(() => console.log('source.txt was copied to destination.txt'))
|
||||
.catch(() => console.log('The file could not be copied'));
|
||||
```
|
||||
|
||||
### fs.promises.fchmod(filehandle, mode)
|
||||
### fsPromises.fchmod(filehandle, mode)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3662,7 +3662,7 @@ added: REPLACEME
|
||||
Asynchronous fchmod(2). The `Promise` is resolved with no arguments upon
|
||||
success.
|
||||
|
||||
### fs.promises.fchown(filehandle, uid, gid)
|
||||
### fsPromises.fchown(filehandle, uid, gid)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3675,7 +3675,7 @@ added: REPLACEME
|
||||
Changes the ownership of the file represented by `filehandle` then resolves
|
||||
the `Promise` with no arguments upon success.
|
||||
|
||||
### fs.promises.fdatasync(filehandle)
|
||||
### fsPromises.fdatasync(filehandle)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3686,7 +3686,7 @@ added: REPLACEME
|
||||
Asynchronous fdatasync(2). The `Promise` is resolved with no arguments upon
|
||||
success.
|
||||
|
||||
### fs.promises.fstat(filehandle)
|
||||
### fsPromises.fstat(filehandle)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3696,7 +3696,7 @@ added: REPLACEME
|
||||
|
||||
Retrieves the [`fs.Stats`][] for the given `filehandle`.
|
||||
|
||||
### fs.promises.fsync(filehandle)
|
||||
### fsPromises.fsync(filehandle)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3707,7 +3707,7 @@ added: REPLACEME
|
||||
Asynchronous fsync(2). The `Promise` is resolved with no arguments upon
|
||||
success.
|
||||
|
||||
### fs.promises.ftruncate(filehandle[, len])
|
||||
### fsPromises.ftruncate(filehandle[, len])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3730,8 +3730,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
|
||||
// Prints: Node.js
|
||||
|
||||
async function doTruncate() {
|
||||
const fd = await fs.promises.open('temp.txt', 'r+');
|
||||
await fs.promises.ftruncate(fd, 4);
|
||||
const fd = await fsPromises.open('temp.txt', 'r+');
|
||||
await fsPromises.ftruncate(fd, 4);
|
||||
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints: Node
|
||||
}
|
||||
|
||||
@ -3746,8 +3746,8 @@ console.log(fs.readFileSync('temp.txt', 'utf8'));
|
||||
// Prints: Node.js
|
||||
|
||||
async function doTruncate() {
|
||||
const fd = await fs.promises.open('temp.txt', 'r+');
|
||||
await fs.promises.ftruncate(fd, 10);
|
||||
const fd = await fsPromises.open('temp.txt', 'r+');
|
||||
await fsPromises.ftruncate(fd, 10);
|
||||
console.log(fs.readFileSync('temp.txt', 'utf8')); // Prints Node.js\0\0\0
|
||||
}
|
||||
|
||||
@ -3756,7 +3756,7 @@ doTruncate().catch(console.error);
|
||||
|
||||
The last three bytes are null bytes ('\0'), to compensate the over-truncation.
|
||||
|
||||
### fs.promises.futimes(filehandle, atime, mtime)
|
||||
### fsPromises.futimes(filehandle, atime, mtime)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3772,7 +3772,7 @@ Change the file system timestamps of the object referenced by the supplied
|
||||
This function does not work on AIX versions before 7.1, it will resolve the
|
||||
`Promise` with an error using code `UV_ENOSYS`.
|
||||
|
||||
### fs.promises.lchmod(path, mode)
|
||||
### fsPromises.lchmod(path, mode)
|
||||
<!-- YAML
|
||||
deprecated: REPLACEME
|
||||
-->
|
||||
@ -3784,7 +3784,7 @@ deprecated: REPLACEME
|
||||
Changes the permissions on a symbolic link then resolves the `Promise` with
|
||||
no arguments upon success. This method is only implemented on macOS.
|
||||
|
||||
### fs.promises.lchown(path, uid, gid)
|
||||
### fsPromises.lchown(path, uid, gid)
|
||||
<!-- YAML
|
||||
deprecated: REPLACEME
|
||||
-->
|
||||
@ -3797,7 +3797,7 @@ deprecated: REPLACEME
|
||||
Changes the ownership on a symbolic link then resolves the `Promise` with
|
||||
no arguments upon success. This method is only implemented on macOS.
|
||||
|
||||
### fs.promises.link(existingPath, newPath)
|
||||
### fsPromises.link(existingPath, newPath)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3808,7 +3808,7 @@ added: REPLACEME
|
||||
|
||||
Asynchronous link(2). The `Promise` is resolved with no arguments upon success.
|
||||
|
||||
### fs.promises.lstat(path)
|
||||
### fsPromises.lstat(path)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3819,7 +3819,7 @@ added: REPLACEME
|
||||
Asynchronous lstat(2). The `Promise` is resolved with the [`fs.Stats`][] object
|
||||
for the given symbolic link `path`.
|
||||
|
||||
### fs.promises.mkdir(path[, mode])
|
||||
### fsPromises.mkdir(path[, mode])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3831,7 +3831,7 @@ added: REPLACEME
|
||||
Asynchronously creates a directory then resolves the `Promise` with no
|
||||
arguments upon success.
|
||||
|
||||
### fs.promises.mkdtemp(prefix[, options])
|
||||
### fsPromises.mkdtemp(prefix[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3851,7 +3851,7 @@ object with an `encoding` property specifying the character encoding to use.
|
||||
Example:
|
||||
|
||||
```js
|
||||
fs.promises.mkdtemp(path.join(os.tmpdir(), 'foo-'))
|
||||
fsPromises.mkdtemp(path.join(os.tmpdir(), 'foo-'))
|
||||
.catch(console.error);
|
||||
```
|
||||
|
||||
@ -3861,7 +3861,7 @@ intention is to create a temporary directory *within* `/tmp`, the `prefix`
|
||||
*must* end with a trailing platform-specific path separator
|
||||
(`require('path').sep`).
|
||||
|
||||
### fs.promises.open(path, flags[, mode])
|
||||
### fsPromises.open(path, flags[, mode])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3889,7 +3889,7 @@ An exception occurs if the file does not exist.
|
||||
the potentially stale local cache. It has a very real impact on I/O
|
||||
performance so using this flag is not recommended unless it is needed.
|
||||
|
||||
Note that this does not turn `fs.promises.open()` into a synchronous blocking
|
||||
Note that this does not turn `fsPromises.open()` into a synchronous blocking
|
||||
call.
|
||||
|
||||
* `'w'` - Open file for writing.
|
||||
@ -3929,7 +3929,7 @@ On Linux, positional writes don't work when the file is opened in append mode.
|
||||
The kernel ignores the position argument and always appends the data to
|
||||
the end of the file.
|
||||
|
||||
The behavior of `fs.promises.open()` is platform-specific for some
|
||||
The behavior of `fsPromises.open()` is platform-specific for some
|
||||
flags. As such, opening a directory on macOS and Linux with the `'a+'` flag will
|
||||
return an error. In contrast, on Windows and FreeBSD, a `FileHandle` will be
|
||||
returned.
|
||||
@ -3940,11 +3940,11 @@ a colon, Node.js will open a file system stream, as described by
|
||||
[this MSDN page][MSDN-Using-Streams].
|
||||
|
||||
*Note:* On Windows, opening an existing hidden file using the `w` flag (e.g.
|
||||
using `fs.promises.open()`) will fail with `EPERM`. Existing hidden
|
||||
using `fsPromises.open()`) will fail with `EPERM`. Existing hidden
|
||||
files can be opened for writing with the `r+` flag. A call to
|
||||
`fs.promises.ftruncate()` can be used to reset the file contents.
|
||||
`fsPromises.ftruncate()` can be used to reset the file contents.
|
||||
|
||||
### fs.promises.read(filehandle, buffer, offset, length, position)
|
||||
### fsPromises.read(filehandle, buffer, offset, length, position)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3973,7 +3973,7 @@ Following successful read, the `Promise` is resolved with an object with a
|
||||
`bytesRead` property specifying the number of bytes read, and a `buffer` property
|
||||
that is a reference to the passed in `buffer` argument.
|
||||
|
||||
### fs.promises.readdir(path[, options])
|
||||
### fsPromises.readdir(path[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -3991,7 +3991,7 @@ object with an `encoding` property specifying the character encoding to use for
|
||||
the filenames. If the `encoding` is set to `'buffer'`, the filenames returned
|
||||
will be passed as `Buffer` objects.
|
||||
|
||||
### fs.promises.readFile(path[, options])
|
||||
### fsPromises.readFile(path[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4010,14 +4010,14 @@ object. Otherwise, the data will be a string.
|
||||
|
||||
If `options` is a string, then it specifies the encoding.
|
||||
|
||||
When the `path` is a directory, the behavior of `fs.promises.readFile()` is
|
||||
When the `path` is a directory, the behavior of `fsPromises.readFile()` is
|
||||
platform-specific. On macOS, Linux, and Windows, the promise will be rejected
|
||||
with an error. On FreeBSD, a representation of the directory's contents will be
|
||||
returned.
|
||||
|
||||
Any specified `FileHandle` has to support reading.
|
||||
|
||||
### fs.promises.readlink(path[, options])
|
||||
### fsPromises.readlink(path[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4035,7 +4035,7 @@ object with an `encoding` property specifying the character encoding to use for
|
||||
the link path returned. If the `encoding` is set to `'buffer'`, the link path
|
||||
returned will be passed as a `Buffer` object.
|
||||
|
||||
### fs.promises.realpath(path[, options])
|
||||
### fsPromises.realpath(path[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4060,7 +4060,7 @@ On Linux, when Node.js is linked against musl libc, the procfs file system must
|
||||
be mounted on `/proc` in order for this function to work. Glibc does not have
|
||||
this restriction.
|
||||
|
||||
### fs.promises.rename(oldPath, newPath)
|
||||
### fsPromises.rename(oldPath, newPath)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4072,7 +4072,7 @@ added: REPLACEME
|
||||
Renames `oldPath` to `newPath` and resolves the `Promise` with no arguments
|
||||
upon success.
|
||||
|
||||
### fs.promises.rmdir(path)
|
||||
### fsPromises.rmdir(path)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4083,11 +4083,11 @@ added: REPLACEME
|
||||
Removes the directory identified by `path` then resolves the `Promise` with
|
||||
no arguments upon success.
|
||||
|
||||
Using `fs.promises.rmdir()` on a file (not a directory) results in the
|
||||
Using `fsPromises.rmdir()` on a file (not a directory) results in the
|
||||
`Promise` being rejected with an `ENOENT` error on Windows and an `ENOTDIR`
|
||||
error on POSIX.
|
||||
|
||||
### fs.promises.stat(path)
|
||||
### fsPromises.stat(path)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4097,7 +4097,7 @@ added: REPLACEME
|
||||
|
||||
The `Promise` is resolved with the [`fs.Stats`][] object for the given `path`.
|
||||
|
||||
### fs.promises.symlink(target, path[, type])
|
||||
### fsPromises.symlink(target, path[, type])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4115,7 +4115,7 @@ The `type` argument is only used on Windows platforms and can be one of `'dir'`,
|
||||
points require the destination path to be absolute. When using `'junction'`,
|
||||
the `target` argument will automatically be normalized to absolute path.
|
||||
|
||||
### fs.promises.truncate(path[, len])
|
||||
### fsPromises.truncate(path[, len])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4127,7 +4127,7 @@ added: REPLACEME
|
||||
Truncates the `path` then resolves the `Promise` with no arguments upon
|
||||
success. The `path` *must* be a string or `Buffer`.
|
||||
|
||||
### fs.promises.unlink(path)
|
||||
### fsPromises.unlink(path)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4138,7 +4138,7 @@ added: REPLACEME
|
||||
Asynchronous unlink(2). The `Promise` is resolved with no arguments upon
|
||||
success.
|
||||
|
||||
### fs.promises.utimes(path, atime, mtime)
|
||||
### fsPromises.utimes(path, atime, mtime)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4157,7 +4157,7 @@ The `atime` and `mtime` arguments follow these rules:
|
||||
- If the value can not be converted to a number, or is `NaN`, `Infinity` or
|
||||
`-Infinity`, an `Error` will be thrown.
|
||||
|
||||
### fs.promises.write(filehandle, buffer[, offset[, length[, position]]])
|
||||
### fsPromises.write(filehandle, buffer[, offset[, length[, position]]])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4182,7 +4182,7 @@ an integer specifying the number of bytes to write.
|
||||
should be written. If `typeof position !== 'number'`, the data will be written
|
||||
at the current position. See pwrite(2).
|
||||
|
||||
It is unsafe to use `fs.promises.write()` multiple times on the same file
|
||||
It is unsafe to use `fsPromises.write()` multiple times on the same file
|
||||
without waiting for the `Promise` to be resolved (or rejected). For this
|
||||
scenario, `fs.createWriteStream` is strongly recommended.
|
||||
|
||||
@ -4190,7 +4190,7 @@ On Linux, positional writes do not work when the file is opened in append mode.
|
||||
The kernel ignores the position argument and always appends the data to
|
||||
the end of the file.
|
||||
|
||||
### fs.promises.writeFile(file, data[, options])
|
||||
### fsPromises.writeFile(file, data[, options])
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
@ -4214,7 +4214,7 @@ If `options` is a string, then it specifies the encoding.
|
||||
|
||||
Any specified `FileHandle` has to support writing.
|
||||
|
||||
It is unsafe to use `fs.promises.writeFile()` multiple times on the same file
|
||||
It is unsafe to use `fsPromises.writeFile()` multiple times on the same file
|
||||
without waiting for the `Promise` to be resolved (or rejected).
|
||||
|
||||
|
||||
|
459
lib/fs.js
459
lib/fs.js
@ -72,9 +72,6 @@ Object.defineProperty(exports, 'constants', {
|
||||
value: constants
|
||||
});
|
||||
|
||||
const kHandle = Symbol('handle');
|
||||
const { kUsePromises } = binding;
|
||||
|
||||
const kMinPoolSpace = 128;
|
||||
const { kMaxLength } = require('buffer');
|
||||
|
||||
@ -2284,459 +2281,3 @@ Object.defineProperty(fs, 'SyncWriteStream', {
|
||||
set: internalUtil.deprecate((val) => { SyncWriteStream = val; },
|
||||
'fs.SyncWriteStream is deprecated.', 'DEP0061')
|
||||
});
|
||||
|
||||
// Promises API
|
||||
|
||||
class FileHandle {
|
||||
constructor(filehandle) {
|
||||
this[kHandle] = filehandle;
|
||||
}
|
||||
|
||||
getAsyncId() {
|
||||
return this[kHandle].getAsyncId();
|
||||
}
|
||||
|
||||
get fd() {
|
||||
return this[kHandle].fd;
|
||||
}
|
||||
|
||||
appendFile(data, options) {
|
||||
return promises.appendFile(this, data, options);
|
||||
}
|
||||
|
||||
chmod(mode) {
|
||||
return promises.fchmod(this, mode);
|
||||
}
|
||||
|
||||
chown(uid, gid) {
|
||||
return promises.fchown(this, uid, gid);
|
||||
}
|
||||
|
||||
datasync() {
|
||||
return promises.fdatasync(this);
|
||||
}
|
||||
|
||||
sync() {
|
||||
return promises.fsync(this);
|
||||
}
|
||||
|
||||
|
||||
read(buffer, offset, length, position) {
|
||||
return promises.read(this, buffer, offset, length, position);
|
||||
}
|
||||
|
||||
readFile(options) {
|
||||
return promises.readFile(this, options);
|
||||
}
|
||||
|
||||
stat() {
|
||||
return promises.fstat(this);
|
||||
}
|
||||
|
||||
truncate(len = 0) {
|
||||
return promises.ftruncate(this, len);
|
||||
}
|
||||
|
||||
utimes(atime, mtime) {
|
||||
return promises.futimes(this, atime, mtime);
|
||||
}
|
||||
|
||||
write(buffer, offset, length, position) {
|
||||
return promises.write(this, buffer, offset, length, position);
|
||||
}
|
||||
|
||||
writeFile(data, options) {
|
||||
return promises.writeFile(this, data, options);
|
||||
}
|
||||
|
||||
close() {
|
||||
return this[kHandle].close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function validateFileHandle(handle) {
|
||||
if (!(handle instanceof FileHandle))
|
||||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
|
||||
'filehandle', 'FileHandle');
|
||||
}
|
||||
|
||||
async function writeFileHandle(filehandle, data, options) {
|
||||
let buffer = isUint8Array(data) ?
|
||||
data : Buffer.from('' + data, options.encoding || 'utf8');
|
||||
let remaining = buffer.length;
|
||||
if (remaining === 0) return;
|
||||
do {
|
||||
const { bytesWritten } =
|
||||
await promises.write(filehandle, buffer, 0,
|
||||
Math.min(16384, buffer.length));
|
||||
remaining -= bytesWritten;
|
||||
buffer = buffer.slice(bytesWritten);
|
||||
} while (remaining > 0);
|
||||
}
|
||||
|
||||
async function readFileHandle(filehandle, options) {
|
||||
const statFields = await binding.fstat(filehandle.fd, kUsePromises);
|
||||
|
||||
let size;
|
||||
if ((statFields[1/*mode*/] & S_IFMT) === S_IFREG) {
|
||||
size = statFields[8/*size*/];
|
||||
} else {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (size === 0)
|
||||
return Buffer.alloc(0);
|
||||
|
||||
if (size > kMaxLength)
|
||||
throw new errors.RangeError('ERR_BUFFER_TOO_LARGE');
|
||||
|
||||
const chunks = [];
|
||||
const chunkSize = Math.min(size, 16384);
|
||||
const buf = Buffer.alloc(chunkSize);
|
||||
let read = 0;
|
||||
do {
|
||||
const { bytesRead, buffer } =
|
||||
await promises.read(filehandle, buf, 0, buf.length);
|
||||
read = bytesRead;
|
||||
if (read > 0)
|
||||
chunks.push(buffer.slice(0, read));
|
||||
} while (read === chunkSize);
|
||||
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
// All of the functions in fs.promises are defined as async in order to
|
||||
// ensure that errors thrown cause promise rejections rather than being
|
||||
// thrown synchronously
|
||||
const promises = {
|
||||
async access(path, mode = fs.F_OK) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
|
||||
mode = mode | 0;
|
||||
return binding.access(pathModule.toNamespacedPath(path), mode,
|
||||
kUsePromises);
|
||||
},
|
||||
|
||||
async copyFile(src, dest, flags) {
|
||||
src = getPathFromURL(src);
|
||||
dest = getPathFromURL(dest);
|
||||
validatePath(src, 'src');
|
||||
validatePath(dest, 'dest');
|
||||
flags = flags | 0;
|
||||
return binding.copyFile(pathModule.toNamespacedPath(src),
|
||||
pathModule.toNamespacedPath(dest),
|
||||
flags, kUsePromises);
|
||||
},
|
||||
|
||||
// Note that unlike fs.open() which uses numeric file descriptors,
|
||||
// promises.open() uses the fs.FileHandle class.
|
||||
async open(path, flags, mode) {
|
||||
mode = modeNum(mode, 0o666);
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
validateUint32(mode, 'mode');
|
||||
return new FileHandle(
|
||||
await binding.openFileHandle(pathModule.toNamespacedPath(path),
|
||||
stringToFlags(flags),
|
||||
mode, kUsePromises));
|
||||
},
|
||||
|
||||
async read(handle, buffer, offset, length, position) {
|
||||
validateFileHandle(handle);
|
||||
validateBuffer(buffer);
|
||||
|
||||
offset |= 0;
|
||||
length |= 0;
|
||||
|
||||
if (length === 0)
|
||||
return { bytesRead: length, buffer };
|
||||
|
||||
validateOffsetLengthRead(offset, length, buffer.length);
|
||||
|
||||
if (!isUint32(position))
|
||||
position = -1;
|
||||
|
||||
const bytesRead = (await binding.read(handle.fd, buffer, offset, length,
|
||||
position, kUsePromises)) || 0;
|
||||
|
||||
return { bytesRead, buffer };
|
||||
},
|
||||
|
||||
async write(handle, buffer, offset, length, position) {
|
||||
validateFileHandle(handle);
|
||||
|
||||
if (buffer.length === 0)
|
||||
return { bytesWritten: 0, buffer };
|
||||
|
||||
if (isUint8Array(buffer)) {
|
||||
if (typeof offset !== 'number')
|
||||
offset = 0;
|
||||
if (typeof length !== 'number')
|
||||
length = buffer.length - offset;
|
||||
if (typeof position !== 'number')
|
||||
position = null;
|
||||
validateOffsetLengthWrite(offset, length, buffer.byteLength);
|
||||
const bytesWritten =
|
||||
(await binding.writeBuffer(handle.fd, buffer, offset,
|
||||
length, position, kUsePromises)) || 0;
|
||||
return { bytesWritten, buffer };
|
||||
}
|
||||
|
||||
if (typeof buffer !== 'string')
|
||||
buffer += '';
|
||||
if (typeof position !== 'function') {
|
||||
if (typeof offset === 'function') {
|
||||
position = offset;
|
||||
offset = null;
|
||||
} else {
|
||||
position = length;
|
||||
}
|
||||
length = 'utf8';
|
||||
}
|
||||
const bytesWritten = (await binding.writeString(handle.fd, buffer, offset,
|
||||
length, kUsePromises)) || 0;
|
||||
return { bytesWritten, buffer };
|
||||
},
|
||||
|
||||
async rename(oldPath, newPath) {
|
||||
oldPath = getPathFromURL(oldPath);
|
||||
newPath = getPathFromURL(newPath);
|
||||
validatePath(oldPath, 'oldPath');
|
||||
validatePath(newPath, 'newPath');
|
||||
return binding.rename(pathModule.toNamespacedPath(oldPath),
|
||||
pathModule.toNamespacedPath(newPath),
|
||||
kUsePromises);
|
||||
},
|
||||
|
||||
async truncate(path, len = 0) {
|
||||
return promises.ftruncate(await promises.open(path, 'r+'), len);
|
||||
},
|
||||
|
||||
async ftruncate(handle, len = 0) {
|
||||
validateFileHandle(handle);
|
||||
validateLen(len);
|
||||
len = Math.max(0, len);
|
||||
return binding.ftruncate(handle.fd, len, kUsePromises);
|
||||
},
|
||||
|
||||
async rmdir(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.rmdir(pathModule.toNamespacedPath(path), kUsePromises);
|
||||
},
|
||||
|
||||
async fdatasync(handle) {
|
||||
validateFileHandle(handle);
|
||||
return binding.fdatasync(handle.fd, kUsePromises);
|
||||
},
|
||||
|
||||
async fsync(handle) {
|
||||
validateFileHandle(handle);
|
||||
return binding.fsync(handle.fd, kUsePromises);
|
||||
},
|
||||
|
||||
async mkdir(path, mode) {
|
||||
mode = modeNum(mode, 0o777);
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
validateUint32(mode, 'mode');
|
||||
return binding.mkdir(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
||||
},
|
||||
|
||||
async readdir(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.readdir(pathModule.toNamespacedPath(path),
|
||||
options.encoding, kUsePromises);
|
||||
},
|
||||
|
||||
async readlink(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path, 'oldPath');
|
||||
return binding.readlink(pathModule.toNamespacedPath(path),
|
||||
options.encoding, kUsePromises);
|
||||
},
|
||||
|
||||
async symlink(target, path, type_) {
|
||||
const type = (typeof type_ === 'string' ? type_ : null);
|
||||
target = getPathFromURL(target);
|
||||
path = getPathFromURL(path);
|
||||
validatePath(target, 'target');
|
||||
validatePath(path);
|
||||
return binding.symlink(preprocessSymlinkDestination(target, type, path),
|
||||
pathModule.toNamespacedPath(path),
|
||||
stringToSymlinkType(type),
|
||||
kUsePromises);
|
||||
},
|
||||
|
||||
async fstat(handle) {
|
||||
validateFileHandle(handle);
|
||||
return statsFromValues(await binding.fstat(handle.fd, kUsePromises));
|
||||
},
|
||||
|
||||
async lstat(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return statsFromValues(
|
||||
await binding.lstat(pathModule.toNamespacedPath(path), kUsePromises));
|
||||
},
|
||||
|
||||
async stat(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return statsFromValues(
|
||||
await binding.stat(pathModule.toNamespacedPath(path), kUsePromises));
|
||||
},
|
||||
|
||||
async link(existingPath, newPath) {
|
||||
existingPath = getPathFromURL(existingPath);
|
||||
newPath = getPathFromURL(newPath);
|
||||
validatePath(existingPath, 'existingPath');
|
||||
validatePath(newPath, 'newPath');
|
||||
return binding.link(pathModule.toNamespacedPath(existingPath),
|
||||
pathModule.toNamespacedPath(newPath),
|
||||
kUsePromises);
|
||||
},
|
||||
|
||||
async unlink(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.unlink(pathModule.toNamespacedPath(path), kUsePromises);
|
||||
},
|
||||
|
||||
async fchmod(handle, mode) {
|
||||
mode = modeNum(mode);
|
||||
validateFileHandle(handle);
|
||||
validateUint32(mode, 'mode');
|
||||
if (mode < 0 || mode > 0o777)
|
||||
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'mode');
|
||||
return binding.fchmod(handle.fd, mode, kUsePromises);
|
||||
},
|
||||
|
||||
async chmod(path, mode) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
mode = modeNum(mode);
|
||||
validateUint32(mode, 'mode');
|
||||
return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
||||
},
|
||||
|
||||
async lchmod(path, mode) {
|
||||
if (constants.O_SYMLINK !== undefined) {
|
||||
const fd = await promises.open(path,
|
||||
constants.O_WRONLY | constants.O_SYMLINK);
|
||||
return promises.fchmod(fd, mode).finally(fd.close.bind(fd));
|
||||
}
|
||||
throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
|
||||
},
|
||||
|
||||
async lchown(path, uid, gid) {
|
||||
if (constants.O_SYMLINK !== undefined) {
|
||||
const fd = await promises.open(path,
|
||||
constants.O_WRONLY | constants.O_SYMLINK);
|
||||
return promises.fchown(fd, uid, gid).finally(fd.close.bind(fd));
|
||||
}
|
||||
throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
|
||||
},
|
||||
|
||||
async fchown(handle, uid, gid) {
|
||||
validateFileHandle(handle);
|
||||
validateUint32(uid, 'uid');
|
||||
validateUint32(gid, 'gid');
|
||||
return binding.fchown(handle.fd, uid, gid, kUsePromises);
|
||||
},
|
||||
|
||||
async chown(path, uid, gid) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
validateUint32(uid, 'uid');
|
||||
validateUint32(gid, 'gid');
|
||||
return binding.chown(pathModule.toNamespacedPath(path),
|
||||
uid, gid, kUsePromises);
|
||||
},
|
||||
|
||||
async utimes(path, atime, mtime) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.utimes(pathModule.toNamespacedPath(path),
|
||||
toUnixTimestamp(atime),
|
||||
toUnixTimestamp(mtime),
|
||||
kUsePromises);
|
||||
},
|
||||
|
||||
async futimes(handle, atime, mtime) {
|
||||
validateFileHandle(handle);
|
||||
atime = toUnixTimestamp(atime, 'atime');
|
||||
mtime = toUnixTimestamp(mtime, 'mtime');
|
||||
return binding.futimes(handle.fd, atime, mtime, kUsePromises);
|
||||
},
|
||||
|
||||
async realpath(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.realpath(path, options.encoding, kUsePromises);
|
||||
},
|
||||
|
||||
async mkdtemp(prefix, options) {
|
||||
options = getOptions(options, {});
|
||||
if (!prefix || typeof prefix !== 'string') {
|
||||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
|
||||
'prefix',
|
||||
'string',
|
||||
prefix);
|
||||
}
|
||||
nullCheck(prefix);
|
||||
return binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, kUsePromises);
|
||||
},
|
||||
|
||||
async writeFile(path, data, options) {
|
||||
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
|
||||
const flag = options.flag || 'w';
|
||||
|
||||
if (path instanceof FileHandle)
|
||||
return writeFileHandle(path, data, options);
|
||||
|
||||
const fd = await promises.open(path, flag, options.mode);
|
||||
return writeFileHandle(fd, data, options).finally(fd.close.bind(fd));
|
||||
},
|
||||
|
||||
async appendFile(path, data, options) {
|
||||
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
|
||||
options = copyObject(options);
|
||||
options.flag = options.flag || 'a';
|
||||
return promises.writeFile(path, data, options);
|
||||
},
|
||||
|
||||
async readFile(path, options) {
|
||||
options = getOptions(options, { flag: 'r' });
|
||||
|
||||
if (path instanceof FileHandle)
|
||||
return readFileHandle(path, options);
|
||||
|
||||
const fd = await promises.open(path, options.flag, 0o666);
|
||||
return readFileHandle(fd, options).finally(fd.close.bind(fd));
|
||||
}
|
||||
};
|
||||
|
||||
let warn = true;
|
||||
|
||||
// TODO(jasnell): Exposing this as a property with a getter works fine with
|
||||
// commonjs but is going to be problematic for named imports support under
|
||||
// ESM. A different approach will have to be followed there.
|
||||
Object.defineProperty(fs, 'promises', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
if (warn) {
|
||||
warn = false;
|
||||
process.emitWarning('The fs.promises API is experimental',
|
||||
'ExperimentalWarning');
|
||||
}
|
||||
return promises;
|
||||
}
|
||||
});
|
||||
|
507
lib/fs/promises.js
Normal file
507
lib/fs/promises.js
Normal file
@ -0,0 +1,507 @@
|
||||
'use strict';
|
||||
|
||||
process.emitWarning('The fs/promises API is experimental',
|
||||
'ExperimentalWarning');
|
||||
|
||||
const {
|
||||
F_OK,
|
||||
O_SYMLINK,
|
||||
O_WRONLY,
|
||||
S_IFMT,
|
||||
S_IFREG
|
||||
} = process.binding('constants').fs;
|
||||
const binding = process.binding('fs');
|
||||
const { Buffer, kMaxLength } = require('buffer');
|
||||
const errors = require('internal/errors');
|
||||
const { getPathFromURL } = require('internal/url');
|
||||
const { isUint8Array } = require('internal/util/types');
|
||||
const {
|
||||
copyObject,
|
||||
getOptions,
|
||||
isUint32,
|
||||
modeNum,
|
||||
nullCheck,
|
||||
preprocessSymlinkDestination,
|
||||
statsFromValues,
|
||||
stringToFlags,
|
||||
stringToSymlinkType,
|
||||
toUnixTimestamp,
|
||||
validateBuffer,
|
||||
validateLen,
|
||||
validateOffsetLengthRead,
|
||||
validateOffsetLengthWrite,
|
||||
validatePath,
|
||||
validateUint32
|
||||
} = require('internal/fs');
|
||||
const pathModule = require('path');
|
||||
|
||||
const kHandle = Symbol('handle');
|
||||
const { kUsePromises } = binding;
|
||||
|
||||
class FileHandle {
|
||||
constructor(filehandle) {
|
||||
this[kHandle] = filehandle;
|
||||
}
|
||||
|
||||
getAsyncId() {
|
||||
return this[kHandle].getAsyncId();
|
||||
}
|
||||
|
||||
get fd() {
|
||||
return this[kHandle].fd;
|
||||
}
|
||||
|
||||
appendFile(data, options) {
|
||||
return appendFile(this, data, options);
|
||||
}
|
||||
|
||||
chmod(mode) {
|
||||
return fchmod(this, mode);
|
||||
}
|
||||
|
||||
chown(uid, gid) {
|
||||
return fchown(this, uid, gid);
|
||||
}
|
||||
|
||||
datasync() {
|
||||
return fdatasync(this);
|
||||
}
|
||||
|
||||
sync() {
|
||||
return fsync(this);
|
||||
}
|
||||
|
||||
read(buffer, offset, length, position) {
|
||||
return read(this, buffer, offset, length, position);
|
||||
}
|
||||
|
||||
readFile(options) {
|
||||
return readFile(this, options);
|
||||
}
|
||||
|
||||
stat() {
|
||||
return fstat(this);
|
||||
}
|
||||
|
||||
truncate(len = 0) {
|
||||
return ftruncate(this, len);
|
||||
}
|
||||
|
||||
utimes(atime, mtime) {
|
||||
return futimes(this, atime, mtime);
|
||||
}
|
||||
|
||||
write(buffer, offset, length, position) {
|
||||
return write(this, buffer, offset, length, position);
|
||||
}
|
||||
|
||||
writeFile(data, options) {
|
||||
return writeFile(this, data, options);
|
||||
}
|
||||
|
||||
close() {
|
||||
return this[kHandle].close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function validateFileHandle(handle) {
|
||||
if (!(handle instanceof FileHandle))
|
||||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
|
||||
'filehandle', 'FileHandle');
|
||||
}
|
||||
|
||||
async function writeFileHandle(filehandle, data, options) {
|
||||
let buffer = isUint8Array(data) ?
|
||||
data : Buffer.from('' + data, options.encoding || 'utf8');
|
||||
let remaining = buffer.length;
|
||||
if (remaining === 0) return;
|
||||
do {
|
||||
const { bytesWritten } =
|
||||
await write(filehandle, buffer, 0,
|
||||
Math.min(16384, buffer.length));
|
||||
remaining -= bytesWritten;
|
||||
buffer = buffer.slice(bytesWritten);
|
||||
} while (remaining > 0);
|
||||
}
|
||||
|
||||
async function readFileHandle(filehandle, options) {
|
||||
const statFields = await binding.fstat(filehandle.fd, kUsePromises);
|
||||
|
||||
let size;
|
||||
if ((statFields[1/*mode*/] & S_IFMT) === S_IFREG) {
|
||||
size = statFields[8/*size*/];
|
||||
} else {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (size === 0)
|
||||
return Buffer.alloc(0);
|
||||
|
||||
if (size > kMaxLength)
|
||||
throw new errors.RangeError('ERR_BUFFER_TOO_LARGE');
|
||||
|
||||
const chunks = [];
|
||||
const chunkSize = Math.min(size, 16384);
|
||||
const buf = Buffer.alloc(chunkSize);
|
||||
let totalRead = 0;
|
||||
do {
|
||||
const { bytesRead, buffer } =
|
||||
await read(filehandle, buf, 0, buf.length);
|
||||
totalRead = bytesRead;
|
||||
if (totalRead > 0)
|
||||
chunks.push(buffer.slice(0, totalRead));
|
||||
} while (totalRead === chunkSize);
|
||||
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
// All of the functions are defined as async in order to ensure that errors
|
||||
// thrown cause promise rejections rather than being thrown synchronously.
|
||||
async function access(path, mode = F_OK) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
|
||||
mode = mode | 0;
|
||||
return binding.access(pathModule.toNamespacedPath(path), mode,
|
||||
kUsePromises);
|
||||
}
|
||||
|
||||
async function copyFile(src, dest, flags) {
|
||||
src = getPathFromURL(src);
|
||||
dest = getPathFromURL(dest);
|
||||
validatePath(src, 'src');
|
||||
validatePath(dest, 'dest');
|
||||
flags = flags | 0;
|
||||
return binding.copyFile(pathModule.toNamespacedPath(src),
|
||||
pathModule.toNamespacedPath(dest),
|
||||
flags, kUsePromises);
|
||||
}
|
||||
|
||||
// Note that unlike fs.open() which uses numeric file descriptors,
|
||||
// fsPromises.open() uses the fs.FileHandle class.
|
||||
async function open(path, flags, mode) {
|
||||
mode = modeNum(mode, 0o666);
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
validateUint32(mode, 'mode');
|
||||
return new FileHandle(
|
||||
await binding.openFileHandle(pathModule.toNamespacedPath(path),
|
||||
stringToFlags(flags),
|
||||
mode, kUsePromises));
|
||||
}
|
||||
|
||||
async function read(handle, buffer, offset, length, position) {
|
||||
validateFileHandle(handle);
|
||||
validateBuffer(buffer);
|
||||
|
||||
offset |= 0;
|
||||
length |= 0;
|
||||
|
||||
if (length === 0)
|
||||
return { bytesRead: length, buffer };
|
||||
|
||||
validateOffsetLengthRead(offset, length, buffer.length);
|
||||
|
||||
if (!isUint32(position))
|
||||
position = -1;
|
||||
|
||||
const bytesRead = (await binding.read(handle.fd, buffer, offset, length,
|
||||
position, kUsePromises)) || 0;
|
||||
|
||||
return { bytesRead, buffer };
|
||||
}
|
||||
|
||||
async function write(handle, buffer, offset, length, position) {
|
||||
validateFileHandle(handle);
|
||||
|
||||
if (buffer.length === 0)
|
||||
return { bytesWritten: 0, buffer };
|
||||
|
||||
if (isUint8Array(buffer)) {
|
||||
if (typeof offset !== 'number')
|
||||
offset = 0;
|
||||
if (typeof length !== 'number')
|
||||
length = buffer.length - offset;
|
||||
if (typeof position !== 'number')
|
||||
position = null;
|
||||
validateOffsetLengthWrite(offset, length, buffer.byteLength);
|
||||
const bytesWritten =
|
||||
(await binding.writeBuffer(handle.fd, buffer, offset,
|
||||
length, position, kUsePromises)) || 0;
|
||||
return { bytesWritten, buffer };
|
||||
}
|
||||
|
||||
if (typeof buffer !== 'string')
|
||||
buffer += '';
|
||||
if (typeof position !== 'function') {
|
||||
if (typeof offset === 'function') {
|
||||
position = offset;
|
||||
offset = null;
|
||||
} else {
|
||||
position = length;
|
||||
}
|
||||
length = 'utf8';
|
||||
}
|
||||
const bytesWritten = (await binding.writeString(handle.fd, buffer, offset,
|
||||
length, kUsePromises)) || 0;
|
||||
return { bytesWritten, buffer };
|
||||
}
|
||||
|
||||
async function rename(oldPath, newPath) {
|
||||
oldPath = getPathFromURL(oldPath);
|
||||
newPath = getPathFromURL(newPath);
|
||||
validatePath(oldPath, 'oldPath');
|
||||
validatePath(newPath, 'newPath');
|
||||
return binding.rename(pathModule.toNamespacedPath(oldPath),
|
||||
pathModule.toNamespacedPath(newPath),
|
||||
kUsePromises);
|
||||
}
|
||||
|
||||
async function truncate(path, len = 0) {
|
||||
return ftruncate(await open(path, 'r+'), len);
|
||||
}
|
||||
|
||||
async function ftruncate(handle, len = 0) {
|
||||
validateFileHandle(handle);
|
||||
validateLen(len);
|
||||
len = Math.max(0, len);
|
||||
return binding.ftruncate(handle.fd, len, kUsePromises);
|
||||
}
|
||||
|
||||
async function rmdir(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.rmdir(pathModule.toNamespacedPath(path), kUsePromises);
|
||||
}
|
||||
|
||||
async function fdatasync(handle) {
|
||||
validateFileHandle(handle);
|
||||
return binding.fdatasync(handle.fd, kUsePromises);
|
||||
}
|
||||
|
||||
async function fsync(handle) {
|
||||
validateFileHandle(handle);
|
||||
return binding.fsync(handle.fd, kUsePromises);
|
||||
}
|
||||
|
||||
async function mkdir(path, mode) {
|
||||
mode = modeNum(mode, 0o777);
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
validateUint32(mode, 'mode');
|
||||
return binding.mkdir(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
||||
}
|
||||
|
||||
async function readdir(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.readdir(pathModule.toNamespacedPath(path),
|
||||
options.encoding, kUsePromises);
|
||||
}
|
||||
|
||||
async function readlink(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path, 'oldPath');
|
||||
return binding.readlink(pathModule.toNamespacedPath(path),
|
||||
options.encoding, kUsePromises);
|
||||
}
|
||||
|
||||
async function symlink(target, path, type_) {
|
||||
const type = (typeof type_ === 'string' ? type_ : null);
|
||||
target = getPathFromURL(target);
|
||||
path = getPathFromURL(path);
|
||||
validatePath(target, 'target');
|
||||
validatePath(path);
|
||||
return binding.symlink(preprocessSymlinkDestination(target, type, path),
|
||||
pathModule.toNamespacedPath(path),
|
||||
stringToSymlinkType(type),
|
||||
kUsePromises);
|
||||
}
|
||||
|
||||
async function fstat(handle) {
|
||||
validateFileHandle(handle);
|
||||
return statsFromValues(await binding.fstat(handle.fd, kUsePromises));
|
||||
}
|
||||
|
||||
async function lstat(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return statsFromValues(
|
||||
await binding.lstat(pathModule.toNamespacedPath(path), kUsePromises));
|
||||
}
|
||||
|
||||
async function stat(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return statsFromValues(
|
||||
await binding.stat(pathModule.toNamespacedPath(path), kUsePromises));
|
||||
}
|
||||
|
||||
async function link(existingPath, newPath) {
|
||||
existingPath = getPathFromURL(existingPath);
|
||||
newPath = getPathFromURL(newPath);
|
||||
validatePath(existingPath, 'existingPath');
|
||||
validatePath(newPath, 'newPath');
|
||||
return binding.link(pathModule.toNamespacedPath(existingPath),
|
||||
pathModule.toNamespacedPath(newPath),
|
||||
kUsePromises);
|
||||
}
|
||||
|
||||
async function unlink(path) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.unlink(pathModule.toNamespacedPath(path), kUsePromises);
|
||||
}
|
||||
|
||||
async function fchmod(handle, mode) {
|
||||
mode = modeNum(mode);
|
||||
validateFileHandle(handle);
|
||||
validateUint32(mode, 'mode');
|
||||
if (mode < 0 || mode > 0o777)
|
||||
throw new errors.RangeError('ERR_OUT_OF_RANGE', 'mode');
|
||||
return binding.fchmod(handle.fd, mode, kUsePromises);
|
||||
}
|
||||
|
||||
async function chmod(path, mode) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
mode = modeNum(mode);
|
||||
validateUint32(mode, 'mode');
|
||||
return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
||||
}
|
||||
|
||||
async function lchmod(path, mode) {
|
||||
if (O_SYMLINK !== undefined) {
|
||||
const fd = await open(path,
|
||||
O_WRONLY | O_SYMLINK);
|
||||
return fchmod(fd, mode).finally(fd.close.bind(fd));
|
||||
}
|
||||
throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
|
||||
}
|
||||
|
||||
async function lchown(path, uid, gid) {
|
||||
if (O_SYMLINK !== undefined) {
|
||||
const fd = await open(path,
|
||||
O_WRONLY | O_SYMLINK);
|
||||
return fchmod(fd, uid, gid).finally(fd.close.bind(fd));
|
||||
}
|
||||
throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED');
|
||||
}
|
||||
|
||||
async function fchown(handle, uid, gid) {
|
||||
validateFileHandle(handle);
|
||||
validateUint32(uid, 'uid');
|
||||
validateUint32(gid, 'gid');
|
||||
return binding.fchown(handle.fd, uid, gid, kUsePromises);
|
||||
}
|
||||
|
||||
async function chown(path, uid, gid) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
validateUint32(uid, 'uid');
|
||||
validateUint32(gid, 'gid');
|
||||
return binding.chown(pathModule.toNamespacedPath(path),
|
||||
uid, gid, kUsePromises);
|
||||
}
|
||||
|
||||
async function utimes(path, atime, mtime) {
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.utimes(pathModule.toNamespacedPath(path),
|
||||
toUnixTimestamp(atime),
|
||||
toUnixTimestamp(mtime),
|
||||
kUsePromises);
|
||||
}
|
||||
|
||||
async function futimes(handle, atime, mtime) {
|
||||
validateFileHandle(handle);
|
||||
atime = toUnixTimestamp(atime, 'atime');
|
||||
mtime = toUnixTimestamp(mtime, 'mtime');
|
||||
return binding.futimes(handle.fd, atime, mtime, kUsePromises);
|
||||
}
|
||||
|
||||
async function realpath(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getPathFromURL(path);
|
||||
validatePath(path);
|
||||
return binding.realpath(path, options.encoding, kUsePromises);
|
||||
}
|
||||
|
||||
async function mkdtemp(prefix, options) {
|
||||
options = getOptions(options, {});
|
||||
if (!prefix || typeof prefix !== 'string') {
|
||||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
|
||||
'prefix',
|
||||
'string',
|
||||
prefix);
|
||||
}
|
||||
nullCheck(prefix);
|
||||
return binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, kUsePromises);
|
||||
}
|
||||
|
||||
async function writeFile(path, data, options) {
|
||||
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
|
||||
const flag = options.flag || 'w';
|
||||
|
||||
if (path instanceof FileHandle)
|
||||
return writeFileHandle(path, data, options);
|
||||
|
||||
const fd = await open(path, flag, options.mode);
|
||||
return writeFileHandle(fd, data, options).finally(fd.close.bind(fd));
|
||||
}
|
||||
|
||||
async function appendFile(path, data, options) {
|
||||
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
|
||||
options = copyObject(options);
|
||||
options.flag = options.flag || 'a';
|
||||
return writeFile(path, data, options);
|
||||
}
|
||||
|
||||
async function readFile(path, options) {
|
||||
options = getOptions(options, { flag: 'r' });
|
||||
|
||||
if (path instanceof FileHandle)
|
||||
return readFileHandle(path, options);
|
||||
|
||||
const fd = await open(path, options.flag, 0o666);
|
||||
return readFileHandle(fd, options).finally(fd.close.bind(fd));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
access,
|
||||
copyFile,
|
||||
open,
|
||||
read,
|
||||
write,
|
||||
rename,
|
||||
truncate,
|
||||
ftruncate,
|
||||
rmdir,
|
||||
fdatasync,
|
||||
fsync,
|
||||
mkdir,
|
||||
readdir,
|
||||
readlink,
|
||||
symlink,
|
||||
fstat,
|
||||
lstat,
|
||||
stat,
|
||||
link,
|
||||
unlink,
|
||||
fchmod,
|
||||
chmod,
|
||||
lchmod,
|
||||
lchown,
|
||||
fchown,
|
||||
chown,
|
||||
utimes,
|
||||
futimes,
|
||||
realpath,
|
||||
mkdtemp,
|
||||
writeFile,
|
||||
appendFile,
|
||||
readFile
|
||||
};
|
1
node.gyp
1
node.gyp
@ -39,6 +39,7 @@
|
||||
'lib/domain.js',
|
||||
'lib/events.js',
|
||||
'lib/fs.js',
|
||||
'lib/fs/promises.js',
|
||||
'lib/http.js',
|
||||
'lib/http2.js',
|
||||
'lib/_http_agent.js',
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const common = require('../common');
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs/promises');
|
||||
const path = require('path');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const assert = require('assert');
|
||||
@ -16,20 +17,20 @@ const buffer = Buffer.from('abc'.repeat(1000));
|
||||
const buffer2 = Buffer.from('xyz'.repeat(1000));
|
||||
|
||||
async function doWrite() {
|
||||
await fs.promises.writeFile(dest, buffer);
|
||||
await fsPromises.writeFile(dest, buffer);
|
||||
const data = fs.readFileSync(dest);
|
||||
assert.deepStrictEqual(data, buffer);
|
||||
}
|
||||
|
||||
async function doAppend() {
|
||||
await fs.promises.appendFile(dest, buffer2);
|
||||
await fsPromises.appendFile(dest, buffer2);
|
||||
const data = fs.readFileSync(dest);
|
||||
const buf = Buffer.concat([buffer, buffer2]);
|
||||
assert.deepStrictEqual(buf, data);
|
||||
}
|
||||
|
||||
async function doRead() {
|
||||
const data = await fs.promises.readFile(dest);
|
||||
const data = await fsPromises.readFile(dest);
|
||||
const buf = fs.readFileSync(dest);
|
||||
assert.deepStrictEqual(buf, data);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ const assert = require('assert');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs/promises');
|
||||
const {
|
||||
access,
|
||||
chmod,
|
||||
@ -32,7 +32,7 @@ const {
|
||||
write,
|
||||
unlink,
|
||||
utimes
|
||||
} = fs.promises;
|
||||
} = fsPromises;
|
||||
|
||||
const tmpDir = tmpdir.path;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs/promises');
|
||||
const net = require('net');
|
||||
const providers = Object.assign({}, process.binding('async_wrap').Providers);
|
||||
const fixtures = require('../common/fixtures');
|
||||
@ -171,7 +172,7 @@ if (common.hasCrypto) { // eslint-disable-line crypto-check
|
||||
|
||||
{
|
||||
async function openTest() {
|
||||
const fd = await fs.promises.open(__filename, 'r');
|
||||
const fd = await fsPromises.open(__filename, 'r');
|
||||
testInitialized(fd, 'FileHandle');
|
||||
await fd.close();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user