Skip to content

Commit 784d84c

Browse files
LiviaMedeirosRafaelGSS
authored andcommitted
fs: add read(buffer[, options]) versions
This adds the following: - `fs.read(fd, buffer[, options], callback)`. - `filehandle.read(buffer[, options])`. PR-URL: #42768 Refs: #42601 Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 68ed3c8 commit 784d84c

File tree

6 files changed

+151
-54
lines changed

6 files changed

+151
-54
lines changed

‎doc/api/fs.md‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,33 @@ Reads data from the file and stores that in the given buffer.
417417
If the file is not modified concurrently, the end-of-file is reached when the
418418
number of bytes read is zero.
419419
420+
#### `filehandle.read(buffer[, options])`
421+
422+
<!-- YAML
423+
added: REPLACEME
424+
-->
425+
426+
* `buffer`{Buffer|TypedArray|DataView} A buffer that will be filled with the
427+
file data read.
428+
* `options`{Object}
429+
* `offset`{integer} The location in the buffer at which to start filling.
430+
**Default:** `0`
431+
* `length`{integer} The number of bytes to read. **Default:**
432+
`buffer.byteLength- offset`
433+
* `position`{integer} The location where to begin reading data from the
434+
file. If `null`, data will be read from the current file position, and
435+
the position will be updated. If `position` is an integer, the current
436+
file position will remain unchanged. **Default:**: `null`
437+
* Returns:{Promise} Fulfills upon success with an object with two properties:
438+
* `bytesRead`{integer} The number of bytes read
439+
* `buffer`{Buffer|TypedArray|DataView} A reference to the passed in `buffer`
440+
argument.
441+
442+
Reads data from the file and stores that in the given buffer.
443+
444+
If the file is not modified concurrently, the end-of-file is reached when the
445+
number of bytes read is zero.
446+
420447
#### `filehandle.readableWebStream()`
421448
422449
<!-- YAML
@@ -3243,6 +3270,28 @@ Similar to the [`fs.read()`][] function, this version takes an optional
32433270
`options` object. If no `options` object is specified, it will default with the
32443271
above values.
32453272
3273+
### `fs.read(fd, buffer[, options], callback)`
3274+
3275+
<!-- YAML
3276+
added: REPLACEME
3277+
-->
3278+
3279+
* `fd`{integer}
3280+
* `buffer`{Buffer|TypedArray|DataView} The buffer that the data will be
3281+
written to.
3282+
* `options`{Object}
3283+
* `offset`{integer} **Default:** `0`
3284+
* `length`{integer} **Default:** `buffer.byteLength- offset`
3285+
* `position`{integer|bigint} **Default:** `null`
3286+
* `callback`{Function}
3287+
* `err`{Error}
3288+
* `bytesRead`{integer}
3289+
* `buffer`{Buffer}
3290+
3291+
Similar to the [`fs.read()`][] function, this version takes an optional
3292+
`options` object. If no `options` object is specified, it will default with the
3293+
above values.
3294+
32463295
### `fs.readdir(path[, options], callback)`
32473296
32483297
<!-- YAML

‎lib/fs.js‎

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ const{
136136
validateEncoding,
137137
validateFunction,
138138
validateInteger,
139+
validateObject,
139140
validateString,
140141
}=require('internal/validators');
141142

@@ -595,7 +596,7 @@ function openSync(path, flags, mode){
595596
* Reads file from the specified `fd` (file descriptor).
596597
* @param{number} fd
597598
* @param{Buffer | TypedArray | DataView} buffer
598-
* @param{number} offset
599+
* @param{number} offsetOrOptions
599600
* @param{number} length
600601
* @param{number | bigint | null} position
601602
* @param{(
@@ -605,30 +606,36 @@ function openSync(path, flags, mode){
605606
* ) => any} callback
606607
* @returns{void}
607608
*/
608-
functionread(fd,buffer,offset,length,position,callback){
609+
functionread(fd,buffer,offsetOrOptions,length,position,callback){
609610
fd=getValidatedFd(fd);
610611

611-
if(arguments.length<=3){
612-
// Assume fs.read(fd, options, callback)
613-
letoptions=ObjectCreate(null);
614-
if(arguments.length<3){
612+
letoffset=offsetOrOptions;
613+
letparams=null;
614+
if(arguments.length<=4){
615+
if(arguments.length===4){
616+
// This is fs.read(fd, buffer, options, callback)
617+
validateObject(offsetOrOptions,'options',{nullable: true});
618+
callback=length;
619+
params=offsetOrOptions;
620+
}elseif(arguments.length===3){
621+
// This is fs.read(fd, bufferOrParams, callback)
622+
if(!isArrayBufferView(buffer)){
623+
// This is fs.read(fd, params, callback)
624+
params=buffer;
625+
({ buffer =Buffer.alloc(16384)}=params??ObjectCreate(null));
626+
}
627+
callback=offsetOrOptions;
628+
}else{
615629
// This is fs.read(fd, callback)
616-
// buffer will be the callback
617630
callback=buffer;
618-
}else{
619-
// This is fs.read(fd,{}, callback)
620-
// buffer will be the options object
621-
// offset is the callback
622-
options=buffer;
623-
callback=offset;
631+
buffer=Buffer.alloc(16384);
624632
}
625633

626634
({
627-
buffer =Buffer.alloc(16384),
628635
offset =0,
629636
length =buffer.byteLength-offset,
630637
position =null
631-
}=options);
638+
}=params??ObjectCreate(null));
632639
}
633640

634641
validateBuffer(buffer);

‎lib/internal/fs/promises.js‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,20 +508,29 @@ async function open(path, flags, mode){
508508
flagsNumber,mode,kUsePromises));
509509
}
510510

511-
asyncfunctionread(handle,bufferOrOptions,offset,length,position){
512-
letbuffer=bufferOrOptions;
511+
asyncfunctionread(handle,bufferOrParams,offset,length,position){
512+
letbuffer=bufferOrParams;
513513
if(!isArrayBufferView(buffer)){
514-
bufferOrOptions??=ObjectCreate(null);
514+
// This is fh.read(params)
515515
({
516516
buffer =Buffer.alloc(16384),
517517
offset =0,
518518
length =buffer.byteLength-offset,
519519
position =null
520-
}=bufferOrOptions);
520+
}=bufferOrParams??ObjectCreate(null));
521521

522522
validateBuffer(buffer);
523523
}
524524

525+
if(offset!==null&&typeofoffset==='object'){
526+
// This is fh.read(buffer, options)
527+
({
528+
offset =0,
529+
length =buffer.byteLength-offset,
530+
position =null
531+
}=offset??ObjectCreate(null));
532+
}
533+
525534
if(offset==null){
526535
offset=0;
527536
}else{

‎test/parallel/test-fs-read-offset-null.js‎

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,51 @@ const filepath = fixtures.path('x.txt');
1414
constbuf=Buffer.alloc(1);
1515
// Reading only one character, hence buffer of one byte is enough.
1616

17-
// Test for callback API.
17+
// Tests are done by making sure the first letter in buffer is
18+
// same as first letter in file.
19+
// 120 is the ascii code of letter x.
20+
21+
// Tests for callback API.
1822
fs.open(filepath,'r',common.mustSucceed((fd)=>{
1923
fs.read(fd,{offset: null,buffer: buf},
2024
common.mustSucceed((bytesRead,buffer)=>{
21-
// Test is done by making sure the first letter in buffer is
22-
// same as first letter in file.
23-
// 120 is the hex for ascii code of letter x.
25+
assert.strictEqual(buffer[0],120);
26+
fs.close(fd,common.mustSucceed(()=>{}));
27+
}));
28+
}));
29+
30+
fs.open(filepath,'r',common.mustSucceed((fd)=>{
31+
fs.read(fd,buf,{offset: null},
32+
common.mustSucceed((bytesRead,buffer)=>{
2433
assert.strictEqual(buffer[0],120);
2534
fs.close(fd,common.mustSucceed(()=>{}));
2635
}));
2736
}));
2837

2938
letfilehandle=null;
3039

31-
// Test for promise api
40+
// Tests for promises api
41+
(async()=>{
42+
filehandle=awaitfsPromises.open(filepath,'r');
43+
constreadObject=awaitfilehandle.read(buf,{offset: null});
44+
assert.strictEqual(readObject.buffer[0],120);
45+
})()
46+
.finally(()=>filehandle?.close())
47+
.then(common.mustCall());
48+
49+
// Undocumented: omitted position works the same as position === null
3250
(async()=>{
3351
filehandle=awaitfsPromises.open(filepath,'r');
3452
constreadObject=awaitfilehandle.read(buf,null,buf.length);
3553
assert.strictEqual(readObject.buffer[0],120);
3654
})()
37-
.then(common.mustCall())
38-
.finally(async()=>{
39-
// Close the file handle if it is opened
40-
if(filehandle)
41-
awaitfilehandle.close();
42-
});
55+
.finally(()=>filehandle?.close())
56+
.then(common.mustCall());
57+
58+
(async()=>{
59+
filehandle=awaitfsPromises.open(filepath,'r');
60+
constreadObject=awaitfilehandle.read(buf,null,buf.length,0);
61+
assert.strictEqual(readObject.buffer[0],120);
62+
})()
63+
.finally(()=>filehandle?.close())
64+
.then(common.mustCall());

‎test/parallel/test-fs-read-optional-params.js‎

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,34 @@ const fixtures = require('../common/fixtures');
55
constfs=require('fs');
66
constassert=require('assert');
77
constfilepath=fixtures.path('x.txt');
8-
constfd=fs.openSync(filepath,'r');
98

109
constexpected=Buffer.from('xyz\n');
1110
constdefaultBufferAsync=Buffer.alloc(16384);
12-
constbufferAsOption=Buffer.allocUnsafe(expected.length);
11+
constbufferAsOption=Buffer.allocUnsafe(expected.byteLength);
1312

14-
// Test not passing in any options object
15-
fs.read(fd,common.mustCall((err,bytesRead,buffer)=>{
16-
assert.strictEqual(bytesRead,expected.length);
17-
assert.deepStrictEqual(defaultBufferAsync.length,buffer.length);
18-
}));
13+
functiontestValid(message, ...options){
14+
constparamsMsg=`${message} (as params)`;
15+
constparamsFilehandle=fs.openSync(filepath,'r');
16+
fs.read(paramsFilehandle, ...options,common.mustSucceed((bytesRead,buffer)=>{
17+
assert.strictEqual(bytesRead,expected.byteLength,paramsMsg);
18+
assert.deepStrictEqual(defaultBufferAsync.byteLength,buffer.byteLength,paramsMsg);
19+
fs.closeSync(paramsFilehandle);
20+
}));
1921

20-
// Test passing in an empty options object
21-
fs.read(fd,{position: 0},common.mustCall((err,bytesRead,buffer)=>{
22-
assert.strictEqual(bytesRead,expected.length);
23-
assert.deepStrictEqual(defaultBufferAsync.length,buffer.length);
24-
}));
22+
constoptionsMsg=`${message} (as options)`;
23+
constoptionsFilehandle=fs.openSync(filepath,'r');
24+
fs.read(optionsFilehandle,bufferAsOption, ...options,common.mustSucceed((bytesRead,buffer)=>{
25+
assert.strictEqual(bytesRead,expected.byteLength,optionsMsg);
26+
assert.deepStrictEqual(bufferAsOption.byteLength,buffer.byteLength,optionsMsg);
27+
fs.closeSync(optionsFilehandle);
28+
}));
29+
}
2530

26-
// Test passing in options
27-
fs.read(fd,{
28-
buffer: bufferAsOption,
31+
testValid('Not passing in any object');
32+
testValid('Passing in a null',null);
33+
testValid('Passing in an empty object',{});
34+
testValid('Passing in an object',{
2935
offset: 0,
30-
length: bufferAsOption.length,
31-
position: 0
32-
},
33-
common.mustCall((err,bytesRead,buffer)=>{
34-
assert.strictEqual(bytesRead,expected.length);
35-
assert.deepStrictEqual(bufferAsOption.length,buffer.length);
36-
}));
36+
length: bufferAsOption.byteLength,
37+
position: 0,
38+
});

‎test/parallel/test-fs-read-promises-optional-params.js‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ const fd = fs.openSync(filepath, 'r');
1010

1111
constexpected=Buffer.from('xyz\n');
1212
constdefaultBufferAsync=Buffer.alloc(16384);
13+
constbufferAsOption=Buffer.allocUnsafe(expected.byteLength);
1314

1415
read(fd,{})
1516
.then(function({ bytesRead, buffer }){
16-
assert.strictEqual(bytesRead,expected.length);
17-
assert.deepStrictEqual(defaultBufferAsync.length,buffer.length);
17+
assert.strictEqual(bytesRead,expected.byteLength);
18+
assert.deepStrictEqual(defaultBufferAsync.byteLength,buffer.byteLength);
19+
})
20+
.then(common.mustCall());
21+
22+
read(fd,bufferAsOption,{position: 0})
23+
.then(function({ bytesRead, buffer }){
24+
assert.strictEqual(bytesRead,expected.byteLength);
25+
assert.deepStrictEqual(bufferAsOption.byteLength,buffer.byteLength);
1826
})
1927
.then(common.mustCall());

0 commit comments

Comments
(0)