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