| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 24140ea commit e323e87
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -546,11 +546,17 @@ close the `FileHandle` automatically. User code must still call the | |||
| 546 | 546 | ||
| 547 | 547 | <!-- YAML | |
| 548 | 548 | added: v10.0.0 | |
| 549 | + changes: | ||
| 550 | + - version: REPLACEME | ||
| 551 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 552 | + description: Added support for the `buffer` option. | ||
| 549 | 553 | --> | |
| 550 | 554 | ||
| 551 | 555 | * `options` {Object|string} | |
| 552 | 556 | * `encoding` {string|null} **Default:** `null` | |
| 553 | 557 | * `signal` {AbortSignal} allows aborting an in-progress readFile | |
| 558 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 559 | + function called with the file size that returns the buffer. | ||
| 554 | 560 | * Returns: {Promise} Fulfills upon a successful read with the contents of the | |
| 555 | 561 | file. If no encoding is specified (using `options.encoding`), the data is | |
| 556 | 562 | returned as a {Buffer} object. Otherwise, the data will be a string. | |
@@ -559,13 +565,51 @@ Asynchronously reads the entire contents of a file. | |||
| 559 | 565 | ||
| 560 | 566 | If `options` is a string, then it specifies the `encoding`. | |
| 561 | 567 | ||
| 568 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 569 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 570 | + supplied buffer is too small to contain the entire file, the operation will | ||
| 571 | + fail. | ||
| 572 | + | ||
| 562 | 573 | The {FileHandle} has to support reading. | |
| 563 | 574 | ||
| 564 | 575 | If one or more `filehandle.read()` calls are made on a file handle and then a | |
| 565 | 576 | `filehandle.readFile()` call is made, the data will be read from the current | |
| 566 | 577 | position till the end of the file. It doesn't always read from the beginning | |
| 567 | 578 | of the file. | |
| 568 | 579 | ||
| 580 | + An example using the `buffer` option with a pre-allocated buffer: | ||
| 581 | + | ||
| 582 | + ```mjs | ||
| 583 | + import { Buffer } from 'node:buffer'; | ||
| 584 | + import { open } from 'node:fs/promises'; | ||
| 585 | + | ||
| 586 | + const file = await open('./some/file/to/read'); | ||
| 587 | + try { | ||
| 588 | + const buf = Buffer.alloc(16384); | ||
| 589 | + const contents = await file.readFile({ buffer: buf }); | ||
| 590 | + console.log(contents); // A view over `buf` containing only the bytes read | ||
| 591 | + } finally { | ||
| 592 | + await file.close(); | ||
| 593 | + } | ||
| 594 | + ``` | ||
| 595 | + | ||
| 596 | + An example using the `buffer` option with a function returning a buffer: | ||
| 597 | + | ||
| 598 | + ```mjs | ||
| 599 | + import { Buffer } from 'node:buffer'; | ||
| 600 | + import { open } from 'node:fs/promises'; | ||
| 601 | + | ||
| 602 | + const file = await open('./some/file/to/read'); | ||
| 603 | + try { | ||
| 604 | + const contents = await file.readFile({ | ||
| 605 | + buffer: (size) => Buffer.alloc(size), | ||
| 606 | + }); | ||
| 607 | + console.log(contents); | ||
| 608 | + } finally { | ||
| 609 | + await file.close(); | ||
| 610 | + } | ||
| 611 | + ``` | ||
| 612 | + | ||
| 569 | 613 | #### `filehandle.readLines([options])` | |
| 570 | 614 | ||
| 571 | 615 | <!-- YAML | |
@@ -1491,6 +1535,9 @@ try { | |||
| 1491 | 1535 | <!-- YAML | |
| 1492 | 1536 | added: v10.0.0 | |
| 1493 | 1537 | changes: | |
| 1538 | + - version: REPLACEME | ||
| 1539 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 1540 | + description: Added support for the `buffer` option. | ||
| 1494 | 1541 | - version: | |
| 1495 | 1542 | - v15.2.0 | |
| 1496 | 1543 | - v14.17.0 | |
@@ -1504,6 +1551,8 @@ changes: | |||
| 1504 | 1551 | * `encoding` {string|null} **Default:** `null` | |
| 1505 | 1552 | * `flag` {string} See [support of file system `flags`][]. **Default:** `'r'`. | |
| 1506 | 1553 | * `signal` {AbortSignal} allows aborting an in-progress readFile | |
| 1554 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 1555 | + function called with the file size that returns the buffer. | ||
| 1507 | 1556 | * Returns: {Promise} Fulfills with the contents of the file. | |
| 1508 | 1557 | ||
| 1509 | 1558 | Asynchronously reads the entire contents of a file. | |
@@ -1513,6 +1562,11 @@ as a {Buffer} object. Otherwise, the data will be a string. | |||
| 1513 | 1562 | ||
| 1514 | 1563 | If `options` is a string, then it specifies the encoding. | |
| 1515 | 1564 | ||
| 1565 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 1566 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 1567 | + supplied buffer is too small to contain the entire file, the promise will be | ||
| 1568 | + rejected. | ||
| 1569 | + | ||
| 1516 | 1570 | When the `path` is a directory, the behavior of `fsPromises.readFile()` is | |
| 1517 | 1571 | platform-specific. On macOS, Linux, and Windows, the promise will be rejected | |
| 1518 | 1572 | with an error. On FreeBSD, a representation of the directory's contents will be | |
@@ -1573,6 +1627,29 @@ system requests but rather the internal buffering `fs.readFile` performs. | |||
| 1573 | 1627 | ||
| 1574 | 1628 | Any specified {FileHandle} has to support reading. | |
| 1575 | 1629 | ||
| 1630 | + An example using the `buffer` option with a pre-allocated buffer: | ||
| 1631 | + | ||
| 1632 | + ```mjs | ||
| 1633 | + import { Buffer } from 'node:buffer'; | ||
| 1634 | + import { readFile } from 'node:fs/promises'; | ||
| 1635 | + | ||
| 1636 | + const buf = Buffer.alloc(16384); | ||
| 1637 | + const contents = await readFile('/path/to/file', { buffer: buf }); | ||
| 1638 | + console.log(contents); // A view over `buf` containing only the bytes read | ||
| 1639 | + ``` | ||
| 1640 | + | ||
| 1641 | + An example using the `buffer` option with a function returning a buffer: | ||
| 1642 | + | ||
| 1643 | + ```mjs | ||
| 1644 | + import { Buffer } from 'node:buffer'; | ||
| 1645 | + import { readFile } from 'node:fs/promises'; | ||
| 1646 | + | ||
| 1647 | + const contents = await readFile('/path/to/file', { | ||
| 1648 | + buffer: (size) => Buffer.alloc(size), | ||
| 1649 | + }); | ||
| 1650 | + console.log(contents); | ||
| 1651 | + ``` | ||
| 1652 | + | ||
| 1576 | 1653 | ### `fsPromises.readlink(path[, options])` | |
| 1577 | 1654 | ||
| 1578 | 1655 | <!-- YAML | |
@@ -3940,6 +4017,9 @@ If `options.withFileTypes` is set to `true`, the `files` array will contain | |||
| 3940 | 4017 | <!-- YAML | |
| 3941 | 4018 | added: v0.1.29 | |
| 3942 | 4019 | changes: | |
| 4020 | + - version: REPLACEME | ||
| 4021 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 4022 | + description: Added support for the `buffer` option. | ||
| 3943 | 4023 | - version: v18.0.0 | |
| 3944 | 4024 | pr-url: https://github.com/nodejs/node/pull/41678 | |
| 3945 | 4025 | description: Passing an invalid callback to the `callback` argument | |
@@ -3981,6 +4061,8 @@ changes: | |||
| 3981 | 4061 | * `encoding` {string|null} **Default:** `null` | |
| 3982 | 4062 | * `flag` {string} See [support of file system `flags`][]. **Default:** `'r'`. | |
| 3983 | 4063 | * `signal` {AbortSignal} allows aborting an in-progress readFile | |
| 4064 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 4065 | + function called with the file size that returns the buffer. | ||
| 3984 | 4066 | * `callback` {Function} | |
| 3985 | 4067 | * `err` {Error|AggregateError} | |
| 3986 | 4068 | * `data` {string|Buffer} | |
@@ -4001,6 +4083,11 @@ contents of the file. | |||
| 4001 | 4083 | ||
| 4002 | 4084 | If no encoding is specified, then the raw buffer is returned. | |
| 4003 | 4085 | ||
| 4086 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 4087 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 4088 | + supplied buffer is too small to contain the entire file, the callback is | ||
| 4089 | + called with an error. | ||
| 4090 | + | ||
| 4004 | 4091 | If `options` is a string, then it specifies the encoding: | |
| 4005 | 4092 | ||
| 4006 | 4093 | ```mjs | |
@@ -4049,6 +4136,33 @@ when possible prefer streaming via `fs.createReadStream()`. | |||
| 4049 | 4136 | Aborting an ongoing request does not abort individual operating | |
| 4050 | 4137 | system requests but rather the internal buffering `fs.readFile` performs. | |
| 4051 | 4138 | ||
| 4139 | + An example using the `buffer` option with a pre-allocated buffer: | ||
| 4140 | + | ||
| 4141 | + ```mjs | ||
| 4142 | + import { Buffer } from 'node:buffer'; | ||
| 4143 | + import { readFile } from 'node:fs'; | ||
| 4144 | + | ||
| 4145 | + const buf = Buffer.alloc(16384); | ||
| 4146 | + readFile('/path/to/file', { buffer: buf }, (err, data) => { | ||
| 4147 | + if (err) throw err; | ||
| 4148 | + console.log(data); // A view over `buf` containing only the bytes read | ||
| 4149 | + }); | ||
| 4150 | + ``` | ||
| 4151 | + | ||
| 4152 | + An example using the `buffer` option with a function returning a buffer: | ||
| 4153 | + | ||
| 4154 | + ```mjs | ||
| 4155 | + import { Buffer } from 'node:buffer'; | ||
| 4156 | + import { readFile } from 'node:fs'; | ||
| 4157 | + | ||
| 4158 | + readFile('/path/to/file', { | ||
| 4159 | + buffer: (size) => Buffer.alloc(size), | ||
| 4160 | + }, (err, data) => { | ||
| 4161 | + if (err) throw err; | ||
| 4162 | + console.log(data); | ||
| 4163 | + }); | ||
| 4164 | + ``` | ||
| 4165 | + | ||
| 4052 | 4166 | #### File descriptors | |
| 4053 | 4167 | ||
| 4054 | 4168 | 1. Any specified file descriptor has to support reading. | |
@@ -6128,6 +6242,9 @@ If `options.withFileTypes` is set to `true`, the result will contain | |||
| 6128 | 6242 | <!-- YAML | |
| 6129 | 6243 | added: v0.1.8 | |
| 6130 | 6244 | changes: | |
| 6245 | + - version: REPLACEME | ||
| 6246 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 6247 | + description: Added support for the `buffer` option. | ||
| 6131 | 6248 | - version: v7.6.0 | |
| 6132 | 6249 | pr-url: https://github.com/nodejs/node/pull/10739 | |
| 6133 | 6250 | description: The `path` parameter can be a WHATWG `URL` object using `file:` | |
@@ -6141,6 +6258,8 @@ changes: | |||
| 6141 | 6258 | * `options` {Object|string} | |
| 6142 | 6259 | * `encoding` {string|null} **Default:** `null` | |
| 6143 | 6260 | * `flag` {string} See [support of file system `flags`][]. **Default:** `'r'`. | |
| 6261 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 6262 | + function called with the file size that returns the buffer. | ||
| 6144 | 6263 | * Returns: {string|Buffer} | |
| 6145 | 6264 | ||
| 6146 | 6265 | Returns the contents of the `path`. | |
@@ -6151,6 +6270,11 @@ this API: [`fs.readFile()`][]. | |||
| 6151 | 6270 | If the `encoding` option is specified then this function returns a | |
| 6152 | 6271 | string. Otherwise it returns a buffer. | |
| 6153 | 6272 | ||
| 6273 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 6274 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 6275 | + supplied buffer is too small to contain the entire file, an error will be | ||
| 6276 | + thrown. | ||
| 6277 | + | ||
| 6154 | 6278 | Similar to [`fs.readFile()`][], when the path is a directory, the behavior of | |
| 6155 | 6279 | `fs.readFileSync()` is platform-specific. | |
| 6156 | 6280 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -116,6 +116,8 @@ const { | |||
| 116 | 116 | handleErrorFromBinding, | |
| 117 | 117 | preprocessSymlinkDestination, | |
| 118 | 118 | Stats, | |
| 119 | + getReadFileBuffer, | ||
| 120 | + getReadFileBufferByteLengthName, | ||
| 119 | 121 | getStatFsFromBinding, | |
| 120 | 122 | getStatsFromBinding, | |
| 121 | 123 | realpathCacheKey, | |
@@ -128,6 +130,7 @@ const { | |||
| 128 | 130 | validateOffsetLengthWrite, | |
| 129 | 131 | validatePath, | |
| 130 | 132 | validatePosition, | |
| 133 | + validateReadFileBufferOptions, | ||
| 131 | 134 | validateRmOptions, | |
| 132 | 135 | validateRmOptionsSync, | |
| 133 | 136 | validateRmdirOptions, | |
@@ -324,13 +327,7 @@ function readFileAfterStat(err, stats) { | |||
| 324 | 327 | } | |
| 325 | 328 | ||
| 326 | 329 | try { | |
| 327 | - if (size === 0) { | ||
| 328 | - // TODO(BridgeAR): If an encoding is set, use the StringDecoder to concat | ||
| 329 | - // the result and reuse the buffer instead of allocating a new one. | ||
| 330 | - context.buffers = []; | ||
| 331 | - } else { | ||
| 332 | - context.buffer = Buffer.allocUnsafeSlow(size); | ||
| 333 | - } | ||
| 330 | + context.prepare(); | ||
| 334 | 331 | } catch (err) { | |
| 335 | 332 | return context.close(err); | |
| 336 | 333 | } | |
@@ -363,8 +360,9 @@ function readFile(path, options, callback) { | |||
| 363 | 360 | callback ||= options; | |
| 364 | 361 | validateFunction(callback, 'cb'); | |
| 365 | 362 | options = getOptions(options, { flag: 'r' }); | |
| 363 | + validateReadFileBufferOptions(options); | ||
| 366 | 364 | ReadFileContext ??= require('internal/fs/read/context'); | |
| 367 | - const context = new ReadFileContext(callback, options.encoding); | ||
| 365 | + const context = new ReadFileContext(callback, options); | ||
| 368 | 366 | context.isUserFd = isFd(path); // File descriptor ownership | |
| 369 | 367 | ||
| 370 | 368 | if (options.signal) { | |
@@ -410,6 +408,18 @@ function tryCreateBuffer(size, fd, isUserFd) { | |||
| 410 | 408 | return buffer; | |
| 411 | 409 | } | |
| 412 | 410 | ||
| 411 | + function tryGetReadFileBuffer(options, size, fd, isUserFd) { | ||
| 412 | + let threw = true; | ||
| 413 | + let buffer; | ||
| 414 | + try { | ||
| 415 | + buffer = getReadFileBuffer(options, size); | ||
| 416 | + threw = false; | ||
| 417 | + } finally { | ||
| 418 | + if (threw && !isUserFd) fs.closeSync(fd); | ||
| 419 | + } | ||
| 420 | + return buffer; | ||
| 421 | + } | ||
| 422 | + | ||
| 413 | 423 | function tryReadSync(fd, isUserFd, buffer, pos, len) { | |
| 414 | 424 | let threw = true; | |
| 415 | 425 | let bytesRead; | |
@@ -422,6 +432,36 @@ function tryReadSync(fd, isUserFd, buffer, pos, len) { | |||
| 422 | 432 | return bytesRead; | |
| 423 | 433 | } | |
| 424 | 434 | ||
| 435 | + function tryReadSyncWithUserBuffer(fd, isUserFd, buffer, byteLengthName) { | ||
| 436 | + let pos = 0; | ||
| 437 | + let bytesRead = 0; | ||
| 438 | + | ||
| 439 | + while (pos < buffer.byteLength) { | ||
| 440 | + bytesRead = tryReadSync(fd, isUserFd, buffer, pos, buffer.byteLength - pos); | ||
| 441 | + pos += bytesRead; | ||
| 442 | + | ||
| 443 | + if (bytesRead === 0) { | ||
| 444 | + return pos; | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + const extraBuffer = tryCreateBuffer(1, fd, isUserFd); | ||
| 449 | + bytesRead = tryReadSync(fd, isUserFd, extraBuffer, 0, 1); | ||
| 450 | + | ||
| 451 | + if (bytesRead !== 0) { | ||
| 452 | + if (!isUserFd) { | ||
| 453 | + fs.closeSync(fd); | ||
| 454 | + } | ||
| 455 | + throw new ERR_INVALID_ARG_VALUE( | ||
| 456 | + byteLengthName, | ||
| 457 | + buffer.byteLength, | ||
| 458 | + 'is too small to contain the entire file', | ||
| 459 | + ); | ||
| 460 | + } | ||
| 461 | + | ||
| 462 | + return pos; | ||
| 463 | + } | ||
| 464 | + | ||
| 425 | 465 | /** | |
| 426 | 466 | * Synchronously reads the entire contents of a file. | |
| 427 | 467 | * @param {string | Buffer | URL | number} path | |
@@ -433,8 +473,11 @@ function tryReadSync(fd, isUserFd, buffer, pos, len) { | |||
| 433 | 473 | */ | |
| 434 | 474 | function readFileSync(path, options) { | |
| 435 | 475 | options = getOptions(options, { flag: 'r' }); | |
| 476 | + validateReadFileBufferOptions(options); | ||
| 477 | + const hasUserBuffer = options.buffer !== undefined; | ||
| 436 | 478 | ||
| 437 | - if (options.encoding === 'utf8' || options.encoding === 'utf-8') { | ||
| 479 | + if ((options.encoding === 'utf8' || options.encoding === 'utf-8') && | ||
| 480 | + !hasUserBuffer) { | ||
| 438 | 481 | if (!isInt32(path)) { | |
| 439 | 482 | path = getValidatedPath(path); | |
| 440 | 483 | } | |
@@ -450,15 +493,31 @@ function readFileSync(path, options) { | |||
| 450 | 493 | let buffer; // Single buffer with file data | |
| 451 | 494 | let buffers; // List for when size is unknown | |
| 452 | 495 | ||
| 453 | - if (size === 0) { | ||
| 496 | + if (hasUserBuffer) { | ||
| 497 | + buffer = tryGetReadFileBuffer(options, size, fd, isUserFd); | ||
| 498 | + } else if (size === 0) { | ||
| 454 | 499 | buffers = []; | |
| 455 | 500 | } else { | |
| 456 | 501 | buffer = tryCreateBuffer(size, fd, isUserFd); | |
| 457 | 502 | } | |
| 458 | 503 | ||
| 459 | 504 | let bytesRead; | |
| 460 | 505 | ||
| 461 | - if (size !== 0) { | ||
| 506 | + if (hasUserBuffer) { | ||
| 507 | + if (size !== 0) { | ||
| 508 | + do { | ||
| 509 | + bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos); | ||
| 510 | + pos += bytesRead; | ||
| 511 | + } while (bytesRead !== 0 && pos < size); | ||
| 512 | + } else { | ||
| 513 | + pos = tryReadSyncWithUserBuffer( | ||
| 514 | + fd, | ||
| 515 | + isUserFd, | ||
| 516 | + buffer, | ||
| 517 | + getReadFileBufferByteLengthName(options), | ||
| 518 | + ); | ||
| 519 | + } | ||
| 520 | + } else if (size !== 0) { | ||
| 462 | 521 | do { | |
| 463 | 522 | bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos); | |
| 464 | 523 | pos += bytesRead; | |
@@ -479,7 +538,9 @@ function readFileSync(path, options) { | |||
| 479 | 538 | if (!isUserFd) | |
| 480 | 539 | fs.closeSync(fd); | |
| 481 | 540 | ||
| 482 | - if (size === 0) { | ||
| 541 | + if (hasUserBuffer) { | ||
| 542 | + buffer = buffer.subarray(0, pos); | ||
| 543 | + } else if (size === 0) { | ||
| 483 | 544 | // Data was collected into the buffers list. | |
| 484 | 545 | buffer = Buffer.concat(buffers, pos); | |
| 485 | 546 | } else if (pos < size) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments