| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9485caa commit b78f5a7
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -694,11 +694,17 @@ close the `FileHandle` automatically. User code must still call the | |||
| 694 | 694 | ||
| 695 | 695 | <!-- YAML | |
| 696 | 696 | added: v10.0.0 | |
| 697 | + changes: | ||
| 698 | + - version: REPLACEME | ||
| 699 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 700 | + description: Added support for the `buffer` option. | ||
| 697 | 701 | --> | |
| 698 | 702 | ||
| 699 | 703 | * `options` {Object|string} | |
| 700 | 704 | * `encoding` {string|null} **Default:** `null` | |
| 701 | 705 | * `signal` {AbortSignal} allows aborting an in-progress readFile | |
| 706 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 707 | + function called with the file size that returns the buffer. | ||
| 702 | 708 | * Returns: {Promise} Fulfills upon a successful read with the contents of the | |
| 703 | 709 | file. If no encoding is specified (using `options.encoding`), the data is | |
| 704 | 710 | returned as a {Buffer} object. Otherwise, the data will be a string. | |
@@ -707,13 +713,51 @@ Asynchronously reads the entire contents of a file. | |||
| 707 | 713 | ||
| 708 | 714 | If `options` is a string, then it specifies the `encoding`. | |
| 709 | 715 | ||
| 716 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 717 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 718 | + supplied buffer is too small to contain the entire file, the operation will | ||
| 719 | + fail. | ||
| 720 | + | ||
| 710 | 721 | The {FileHandle} has to support reading. | |
| 711 | 722 | ||
| 712 | 723 | If one or more `filehandle.read()` calls are made on a file handle and then a | |
| 713 | 724 | `filehandle.readFile()` call is made, the data will be read from the current | |
| 714 | 725 | position till the end of the file. It doesn't always read from the beginning | |
| 715 | 726 | of the file. | |
| 716 | 727 | ||
| 728 | + An example using the `buffer` option with a pre-allocated buffer: | ||
| 729 | + | ||
| 730 | + ```mjs | ||
| 731 | + import { Buffer } from 'node:buffer'; | ||
| 732 | + import { open } from 'node:fs/promises'; | ||
| 733 | + | ||
| 734 | + const file = await open('./some/file/to/read'); | ||
| 735 | + try { | ||
| 736 | + const buf = Buffer.alloc(16384); | ||
| 737 | + const contents = await file.readFile({ buffer: buf }); | ||
| 738 | + console.log(contents); // A view over `buf` containing only the bytes read | ||
| 739 | + } finally { | ||
| 740 | + await file.close(); | ||
| 741 | + } | ||
| 742 | + ``` | ||
| 743 | + | ||
| 744 | + An example using the `buffer` option with a function returning a buffer: | ||
| 745 | + | ||
| 746 | + ```mjs | ||
| 747 | + import { Buffer } from 'node:buffer'; | ||
| 748 | + import { open } from 'node:fs/promises'; | ||
| 749 | + | ||
| 750 | + const file = await open('./some/file/to/read'); | ||
| 751 | + try { | ||
| 752 | + const contents = await file.readFile({ | ||
| 753 | + buffer: (size) => Buffer.alloc(size), | ||
| 754 | + }); | ||
| 755 | + console.log(contents); | ||
| 756 | + } finally { | ||
| 757 | + await file.close(); | ||
| 758 | + } | ||
| 759 | + ``` | ||
| 760 | + | ||
| 717 | 761 | #### `filehandle.readLines([options])` | |
| 718 | 762 | ||
| 719 | 763 | <!-- YAML | |
@@ -1758,6 +1802,9 @@ try { | |||
| 1758 | 1802 | <!-- YAML | |
| 1759 | 1803 | added: v10.0.0 | |
| 1760 | 1804 | changes: | |
| 1805 | + - version: REPLACEME | ||
| 1806 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 1807 | + description: Added support for the `buffer` option. | ||
| 1761 | 1808 | - version: | |
| 1762 | 1809 | - v15.2.0 | |
| 1763 | 1810 | - v14.17.0 | |
@@ -1771,6 +1818,8 @@ changes: | |||
| 1771 | 1818 | * `encoding` {string|null} **Default:** `null` | |
| 1772 | 1819 | * `flag` {string} See [support of file system `flags`][]. **Default:** `'r'`. | |
| 1773 | 1820 | * `signal` {AbortSignal} allows aborting an in-progress readFile | |
| 1821 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 1822 | + function called with the file size that returns the buffer. | ||
| 1774 | 1823 | * Returns: {Promise} Fulfills with the contents of the file. | |
| 1775 | 1824 | ||
| 1776 | 1825 | Asynchronously reads the entire contents of a file. | |
@@ -1780,6 +1829,11 @@ as a {Buffer} object. Otherwise, the data will be a string. | |||
| 1780 | 1829 | ||
| 1781 | 1830 | If `options` is a string, then it specifies the encoding. | |
| 1782 | 1831 | ||
| 1832 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 1833 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 1834 | + supplied buffer is too small to contain the entire file, the promise will be | ||
| 1835 | + rejected. | ||
| 1836 | + | ||
| 1783 | 1837 | When the `path` is a directory, the behavior of `fsPromises.readFile()` is | |
| 1784 | 1838 | platform-specific. On macOS, Linux, and Windows, the promise will be rejected | |
| 1785 | 1839 | with an error. On FreeBSD, a representation of the directory's contents will be | |
@@ -1840,6 +1894,29 @@ system requests but rather the internal buffering `fs.readFile` performs. | |||
| 1840 | 1894 | ||
| 1841 | 1895 | Any specified {FileHandle} has to support reading. | |
| 1842 | 1896 | ||
| 1897 | + An example using the `buffer` option with a pre-allocated buffer: | ||
| 1898 | + | ||
| 1899 | + ```mjs | ||
| 1900 | + import { Buffer } from 'node:buffer'; | ||
| 1901 | + import { readFile } from 'node:fs/promises'; | ||
| 1902 | + | ||
| 1903 | + const buf = Buffer.alloc(16384); | ||
| 1904 | + const contents = await readFile('/path/to/file', { buffer: buf }); | ||
| 1905 | + console.log(contents); // A view over `buf` containing only the bytes read | ||
| 1906 | + ``` | ||
| 1907 | + | ||
| 1908 | + An example using the `buffer` option with a function returning a buffer: | ||
| 1909 | + | ||
| 1910 | + ```mjs | ||
| 1911 | + import { Buffer } from 'node:buffer'; | ||
| 1912 | + import { readFile } from 'node:fs/promises'; | ||
| 1913 | + | ||
| 1914 | + const contents = await readFile('/path/to/file', { | ||
| 1915 | + buffer: (size) => Buffer.alloc(size), | ||
| 1916 | + }); | ||
| 1917 | + console.log(contents); | ||
| 1918 | + ``` | ||
| 1919 | + | ||
| 1843 | 1920 | ### `fsPromises.readlink(path[, options])` | |
| 1844 | 1921 | ||
| 1845 | 1922 | <!-- YAML | |
@@ -4216,6 +4293,9 @@ If `options.withFileTypes` is set to `true`, the `files` array will contain | |||
| 4216 | 4293 | <!-- YAML | |
| 4217 | 4294 | added: v0.1.29 | |
| 4218 | 4295 | changes: | |
| 4296 | + - version: REPLACEME | ||
| 4297 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 4298 | + description: Added support for the `buffer` option. | ||
| 4219 | 4299 | - version: v18.0.0 | |
| 4220 | 4300 | pr-url: https://github.com/nodejs/node/pull/41678 | |
| 4221 | 4301 | description: Passing an invalid callback to the `callback` argument | |
@@ -4257,6 +4337,8 @@ changes: | |||
| 4257 | 4337 | * `encoding` {string|null} **Default:** `null` | |
| 4258 | 4338 | * `flag` {string} See [support of file system `flags`][]. **Default:** `'r'`. | |
| 4259 | 4339 | * `signal` {AbortSignal} allows aborting an in-progress readFile | |
| 4340 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 4341 | + function called with the file size that returns the buffer. | ||
| 4260 | 4342 | * `callback` {Function} | |
| 4261 | 4343 | * `err` {Error|AggregateError} | |
| 4262 | 4344 | * `data` {string|Buffer} | |
@@ -4277,6 +4359,11 @@ contents of the file. | |||
| 4277 | 4359 | ||
| 4278 | 4360 | If no encoding is specified, then the raw buffer is returned. | |
| 4279 | 4361 | ||
| 4362 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 4363 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 4364 | + supplied buffer is too small to contain the entire file, the callback is | ||
| 4365 | + called with an error. | ||
| 4366 | + | ||
| 4280 | 4367 | If `options` is a string, then it specifies the encoding: | |
| 4281 | 4368 | ||
| 4282 | 4369 | ```mjs | |
@@ -4325,6 +4412,33 @@ when possible prefer streaming via `fs.createReadStream()`. | |||
| 4325 | 4412 | Aborting an ongoing request does not abort individual operating | |
| 4326 | 4413 | system requests but rather the internal buffering `fs.readFile` performs. | |
| 4327 | 4414 | ||
| 4415 | + An example using the `buffer` option with a pre-allocated buffer: | ||
| 4416 | + | ||
| 4417 | + ```mjs | ||
| 4418 | + import { Buffer } from 'node:buffer'; | ||
| 4419 | + import { readFile } from 'node:fs'; | ||
| 4420 | + | ||
| 4421 | + const buf = Buffer.alloc(16384); | ||
| 4422 | + readFile('/path/to/file', { buffer: buf }, (err, data) => { | ||
| 4423 | + if (err) throw err; | ||
| 4424 | + console.log(data); // A view over `buf` containing only the bytes read | ||
| 4425 | + }); | ||
| 4426 | + ``` | ||
| 4427 | + | ||
| 4428 | + An example using the `buffer` option with a function returning a buffer: | ||
| 4429 | + | ||
| 4430 | + ```mjs | ||
| 4431 | + import { Buffer } from 'node:buffer'; | ||
| 4432 | + import { readFile } from 'node:fs'; | ||
| 4433 | + | ||
| 4434 | + readFile('/path/to/file', { | ||
| 4435 | + buffer: (size) => Buffer.alloc(size), | ||
| 4436 | + }, (err, data) => { | ||
| 4437 | + if (err) throw err; | ||
| 4438 | + console.log(data); | ||
| 4439 | + }); | ||
| 4440 | + ``` | ||
| 4441 | + | ||
| 4328 | 4442 | #### File descriptors | |
| 4329 | 4443 | ||
| 4330 | 4444 | 1. Any specified file descriptor has to support reading. | |
@@ -6415,6 +6529,9 @@ If `options.withFileTypes` is set to `true`, the result will contain | |||
| 6415 | 6529 | <!-- YAML | |
| 6416 | 6530 | added: v0.1.8 | |
| 6417 | 6531 | changes: | |
| 6532 | + - version: REPLACEME | ||
| 6533 | + pr-url: https://github.com/nodejs/node/pull/63634 | ||
| 6534 | + description: Added support for the `buffer` option. | ||
| 6418 | 6535 | - version: v7.6.0 | |
| 6419 | 6536 | pr-url: https://github.com/nodejs/node/pull/10739 | |
| 6420 | 6537 | description: The `path` parameter can be a WHATWG `URL` object using `file:` | |
@@ -6428,6 +6545,8 @@ changes: | |||
| 6428 | 6545 | * `options` {Object|string} | |
| 6429 | 6546 | * `encoding` {string|null} **Default:** `null` | |
| 6430 | 6547 | * `flag` {string} See [support of file system `flags`][]. **Default:** `'r'`. | |
| 6548 | + * `buffer` {Buffer|TypedArray|DataView|Function} A buffer to read into, or a | ||
| 6549 | + function called with the file size that returns the buffer. | ||
| 6431 | 6550 | * Returns: {string|Buffer} | |
| 6432 | 6551 | ||
| 6433 | 6552 | Returns the contents of the `path`. | |
@@ -6438,6 +6557,11 @@ this API: [`fs.readFile()`][]. | |||
| 6438 | 6557 | If the `encoding` option is specified then this function returns a | |
| 6439 | 6558 | string. Otherwise it returns a buffer. | |
| 6440 | 6559 | ||
| 6560 | + If `buffer` is provided and no encoding is specified, the returned {Buffer} is | ||
| 6561 | + a view over the supplied buffer containing only the bytes read. If the | ||
| 6562 | + supplied buffer is too small to contain the entire file, an error will be | ||
| 6563 | + thrown. | ||
| 6564 | + | ||
| 6441 | 6565 | Similar to [`fs.readFile()`][], when the path is a directory, the behavior of | |
| 6442 | 6566 | `fs.readFileSync()` is platform-specific. | |
| 6443 | 6567 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -111,6 +111,8 @@ const { | |||
| 111 | 111 | handleErrorFromBinding, | |
| 112 | 112 | preprocessSymlinkDestination, | |
| 113 | 113 | Stats, | |
| 114 | + getReadFileBuffer, | ||
| 115 | + getReadFileBufferByteLengthName, | ||
| 114 | 116 | getStatFsFromBinding, | |
| 115 | 117 | getStatsFromBinding, | |
| 116 | 118 | realpathCacheKey, | |
@@ -123,6 +125,7 @@ const { | |||
| 123 | 125 | validateOffsetLengthWrite, | |
| 124 | 126 | validatePath, | |
| 125 | 127 | validatePosition, | |
| 128 | + validateReadFileBufferOptions, | ||
| 126 | 129 | validateRmOptions, | |
| 127 | 130 | validateRmOptionsSync, | |
| 128 | 131 | validateRmdirOptions, | |
@@ -319,13 +322,7 @@ function readFileAfterStat(err, stats) { | |||
| 319 | 322 | } | |
| 320 | 323 | ||
| 321 | 324 | try { | |
| 322 | - if (size === 0) { | ||
| 323 | - // TODO(BridgeAR): If an encoding is set, use the StringDecoder to concat | ||
| 324 | - // the result and reuse the buffer instead of allocating a new one. | ||
| 325 | - context.buffers = []; | ||
| 326 | - } else { | ||
| 327 | - context.buffer = Buffer.allocUnsafeSlow(size); | ||
| 328 | - } | ||
| 325 | + context.prepare(); | ||
| 329 | 326 | } catch (err) { | |
| 330 | 327 | return context.close(err); | |
| 331 | 328 | } | |
@@ -358,8 +355,9 @@ function readFile(path, options, callback) { | |||
| 358 | 355 | callback ||= options; | |
| 359 | 356 | validateFunction(callback, 'cb'); | |
| 360 | 357 | options = getOptions(options, { flag: 'r' }); | |
| 358 | + validateReadFileBufferOptions(options); | ||
| 361 | 359 | ReadFileContext ??= require('internal/fs/read/context'); | |
| 362 | - const context = new ReadFileContext(callback, options.encoding); | ||
| 360 | + const context = new ReadFileContext(callback, options); | ||
| 363 | 361 | context.isUserFd = isFd(path); // File descriptor ownership | |
| 364 | 362 | ||
| 365 | 363 | if (options.signal) { | |
@@ -405,6 +403,18 @@ function tryCreateBuffer(size, fd, isUserFd) { | |||
| 405 | 403 | return buffer; | |
| 406 | 404 | } | |
| 407 | 405 | ||
| 406 | + function tryGetReadFileBuffer(options, size, fd, isUserFd) { | ||
| 407 | + let threw = true; | ||
| 408 | + let buffer; | ||
| 409 | + try { | ||
| 410 | + buffer = getReadFileBuffer(options, size); | ||
| 411 | + threw = false; | ||
| 412 | + } finally { | ||
| 413 | + if (threw && !isUserFd) fs.closeSync(fd); | ||
| 414 | + } | ||
| 415 | + return buffer; | ||
| 416 | + } | ||
| 417 | + | ||
| 408 | 418 | function tryReadSync(fd, isUserFd, buffer, pos, len) { | |
| 409 | 419 | let threw = true; | |
| 410 | 420 | let bytesRead; | |
@@ -417,6 +427,36 @@ function tryReadSync(fd, isUserFd, buffer, pos, len) { | |||
| 417 | 427 | return bytesRead; | |
| 418 | 428 | } | |
| 419 | 429 | ||
| 430 | + function tryReadSyncWithUserBuffer(fd, isUserFd, buffer, byteLengthName) { | ||
| 431 | + let pos = 0; | ||
| 432 | + let bytesRead = 0; | ||
| 433 | + | ||
| 434 | + while (pos < buffer.byteLength) { | ||
| 435 | + bytesRead = tryReadSync(fd, isUserFd, buffer, pos, buffer.byteLength - pos); | ||
| 436 | + pos += bytesRead; | ||
| 437 | + | ||
| 438 | + if (bytesRead === 0) { | ||
| 439 | + return pos; | ||
| 440 | + } | ||
| 441 | + } | ||
| 442 | + | ||
| 443 | + const extraBuffer = tryCreateBuffer(1, fd, isUserFd); | ||
| 444 | + bytesRead = tryReadSync(fd, isUserFd, extraBuffer, 0, 1); | ||
| 445 | + | ||
| 446 | + if (bytesRead !== 0) { | ||
| 447 | + if (!isUserFd) { | ||
| 448 | + fs.closeSync(fd); | ||
| 449 | + } | ||
| 450 | + throw new ERR_INVALID_ARG_VALUE( | ||
| 451 | + byteLengthName, | ||
| 452 | + buffer.byteLength, | ||
| 453 | + 'is too small to contain the entire file', | ||
| 454 | + ); | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + return pos; | ||
| 458 | + } | ||
| 459 | + | ||
| 420 | 460 | /** | |
| 421 | 461 | * Synchronously reads the entire contents of a file. | |
| 422 | 462 | * @param {string | Buffer | URL | number} path | |
@@ -428,8 +468,11 @@ function tryReadSync(fd, isUserFd, buffer, pos, len) { | |||
| 428 | 468 | */ | |
| 429 | 469 | function readFileSync(path, options) { | |
| 430 | 470 | options = getOptions(options, { flag: 'r' }); | |
| 471 | + validateReadFileBufferOptions(options); | ||
| 472 | + const hasUserBuffer = options.buffer !== undefined; | ||
| 431 | 473 | ||
| 432 | - if (options.encoding === 'utf8' || options.encoding === 'utf-8') { | ||
| 474 | + if ((options.encoding === 'utf8' || options.encoding === 'utf-8') && | ||
| 475 | + !hasUserBuffer) { | ||
| 433 | 476 | if (!isInt32(path)) { | |
| 434 | 477 | path = getValidatedPath(path); | |
| 435 | 478 | } | |
@@ -445,15 +488,31 @@ function readFileSync(path, options) { | |||
| 445 | 488 | let buffer; // Single buffer with file data | |
| 446 | 489 | let buffers; // List for when size is unknown | |
| 447 | 490 | ||
| 448 | - if (size === 0) { | ||
| 491 | + if (hasUserBuffer) { | ||
| 492 | + buffer = tryGetReadFileBuffer(options, size, fd, isUserFd); | ||
| 493 | + } else if (size === 0) { | ||
| 449 | 494 | buffers = []; | |
| 450 | 495 | } else { | |
| 451 | 496 | buffer = tryCreateBuffer(size, fd, isUserFd); | |
| 452 | 497 | } | |
| 453 | 498 | ||
| 454 | 499 | let bytesRead; | |
| 455 | 500 | ||
| 456 | - if (size !== 0) { | ||
| 501 | + if (hasUserBuffer) { | ||
| 502 | + if (size !== 0) { | ||
| 503 | + do { | ||
| 504 | + bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos); | ||
| 505 | + pos += bytesRead; | ||
| 506 | + } while (bytesRead !== 0 && pos < size); | ||
| 507 | + } else { | ||
| 508 | + pos = tryReadSyncWithUserBuffer( | ||
| 509 | + fd, | ||
| 510 | + isUserFd, | ||
| 511 | + buffer, | ||
| 512 | + getReadFileBufferByteLengthName(options), | ||
| 513 | + ); | ||
| 514 | + } | ||
| 515 | + } else if (size !== 0) { | ||
| 457 | 516 | do { | |
| 458 | 517 | bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos); | |
| 459 | 518 | pos += bytesRead; | |
@@ -474,7 +533,9 @@ function readFileSync(path, options) { | |||
| 474 | 533 | if (!isUserFd) | |
| 475 | 534 | fs.closeSync(fd); | |
| 476 | 535 | ||
| 477 | - if (size === 0) { | ||
| 536 | + if (hasUserBuffer) { | ||
| 537 | + buffer = buffer.subarray(0, pos); | ||
| 538 | + } else if (size === 0) { | ||
| 478 | 539 | // Data was collected into the buffers list. | |
| 479 | 540 | buffer = Buffer.concat(buffers, pos); | |
| 480 | 541 | } else if (pos < size) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments