@@ -87,6 +87,7 @@ const {
87
87
promisify,
88
88
} = require ( 'internal/util' ) ;
89
89
const { EventEmitterMixin } = require ( 'internal/event_target' ) ;
90
+ const { StringDecoder } = require ( 'string_decoder' ) ;
90
91
const { watch } = require ( 'internal/fs/watchers' ) ;
91
92
const { isIterable } = require ( 'internal/streams/utils' ) ;
92
93
const assert = require ( 'internal/assert' ) ;
@@ -419,63 +420,85 @@ async function writeFileHandle(filehandle, data, signal, encoding) {
419
420
420
421
async function readFileHandle ( filehandle , options ) {
421
422
const signal = options ?. signal ;
423
+ const encoding = options ?. encoding ;
424
+ const decoder = encoding && new StringDecoder ( encoding ) ;
422
425
423
426
checkAborted ( signal ) ;
424
427
425
428
const statFields = await binding . fstat ( filehandle . fd , false , kUsePromises ) ;
426
429
427
430
checkAborted ( signal ) ;
428
431
429
- let size ;
432
+ let size = 0 ;
433
+ let length = 0 ;
430
434
if ( ( statFields [ 1 /* mode */ ] & S_IFMT ) === S_IFREG ) {
431
435
size = statFields [ 8 /* size */ ] ;
432
- } else {
433
- size = 0 ;
436
+ length = encoding ? MathMin ( size , kReadFileBufferLength ) : size ;
437
+ }
438
+ if ( length === 0 ) {
439
+ length = kReadFileUnknownBufferLength ;
434
440
}
435
441
436
442
if ( size > kIoMaxLength )
437
443
throw new ERR_FS_FILE_TOO_LARGE ( size ) ;
438
444
439
- let endOfFile = false ;
440
445
let totalRead = 0 ;
441
- const noSize = size === 0 ;
442
- const buffers = [ ] ;
443
- const fullBuffer = noSize ? undefined : Buffer . allocUnsafeSlow ( size ) ;
444
- do {
446
+ let buffer = Buffer . allocUnsafeSlow ( length ) ;
447
+ let result = '' ;
448
+ let offset = 0 ;
449
+ let buffers ;
450
+ const chunkedRead = length > kReadFileBufferLength ;
451
+
452
+ while ( true ) {
445
453
checkAborted ( signal ) ;
446
- let buffer ;
447
- let offset ;
448
- let length ;
449
- if ( noSize ) {
450
- buffer = Buffer . allocUnsafeSlow ( kReadFileUnknownBufferLength ) ;
451
- offset = 0 ;
452
- length = kReadFileUnknownBufferLength ;
453
- } else {
454
- buffer = fullBuffer ;
455
- offset = totalRead ;
454
+
455
+ if ( chunkedRead ) {
456
456
length = MathMin ( size - totalRead , kReadFileBufferLength ) ;
457
457
}
458
458
459
459
const bytesRead = ( await binding . read ( filehandle . fd , buffer , offset ,
460
- length , - 1 , kUsePromises ) ) || 0 ;
460
+ length , - 1 , kUsePromises ) ) ?? 0 ;
461
461
totalRead += bytesRead ;
462
- endOfFile = bytesRead === 0 || totalRead === size ;
463
- if ( noSize && bytesRead > 0 ) {
464
- const isBufferFull = bytesRead === kReadFileUnknownBufferLength ;
465
- const chunkBuffer = isBufferFull ? buffer : buffer . slice ( 0 , bytesRead ) ;
466
- ArrayPrototypePush ( buffers , chunkBuffer ) ;
462
+
463
+ if ( bytesRead === 0 ||
464
+ totalRead === size ||
465
+ ( bytesRead !== buffer . length && ! chunkedRead ) ) {
466
+ const singleRead = bytesRead === totalRead ;
467
+
468
+ const bytesToCheck = chunkedRead ? totalRead : bytesRead ;
469
+
470
+ if ( bytesToCheck !== buffer . length ) {
471
+ buffer = buffer . slice ( 0 , bytesToCheck ) ;
472
+ }
473
+
474
+ if ( ! encoding ) {
475
+ if ( size === 0 && ! singleRead ) {
476
+ ArrayPrototypePush ( buffers , buffer ) ;
477
+ return Buffer . concat ( buffers , totalRead ) ;
478
+ }
479
+ return buffer ;
480
+ }
481
+
482
+ if ( singleRead ) {
483
+ return buffer . toString ( encoding ) ;
484
+ }
485
+ result += decoder . end ( buffer ) ;
486
+ return result ;
467
487
}
468
- } while ( ! endOfFile ) ;
469
488
470
- let result ;
471
- if ( size > 0 ) {
472
- result = totalRead === size ? fullBuffer : fullBuffer . slice ( 0 , totalRead ) ;
473
- } else {
474
- result = buffers . length === 1 ? buffers [ 0 ] : Buffer . concat ( buffers ,
475
- totalRead ) ;
489
+ if ( encoding ) {
490
+ result += decoder . write ( buffer ) ;
491
+ } else if ( size !== 0 ) {
492
+ // TODO(BridgeAR): This condition needs a test. A file should be read
493
+ // that is chunked without encoding.
494
+ offset = totalRead ;
495
+ } else {
496
+ buffers ??= [ ] ;
497
+ // Unknown file size requires chunks.
498
+ ArrayPrototypePush ( buffers , buffer ) ;
499
+ buffer = Buffer . allocUnsafeSlow ( kReadFileUnknownBufferLength ) ;
500
+ }
476
501
}
477
-
478
- return options . encoding ? result . toString ( options . encoding ) : result ;
479
502
}
480
503
481
504
// All of the functions are defined as async in order to ensure that errors
0 commit comments