@@ -86,6 +86,7 @@ const {
8686 promisify,
8787} = require ( 'internal/util' ) ;
8888const { EventEmitterMixin } = require ( 'internal/event_target' ) ;
89+ const { StringDecoder } = require ( 'string_decoder' ) ;
8990const { watch } = require ( 'internal/fs/watchers' ) ;
9091const { isIterable } = require ( 'internal/streams/utils' ) ;
9192const assert = require ( 'internal/assert' ) ;
@@ -416,63 +417,83 @@ async function writeFileHandle(filehandle, data, signal, encoding) {
416417
417418async function readFileHandle ( filehandle , options ) {
418419 const signal = options ?. signal ;
420+ const encoding = options ?. encoding ;
421+ const decoder = encoding && new StringDecoder ( encoding ) ;
419422
420423 checkAborted ( signal ) ;
421424
422425 const statFields = await binding . fstat ( filehandle . fd , false , kUsePromises ) ;
423426
424427 checkAborted ( signal ) ;
425428
426- let size ;
429+ let size = 0 ;
430+ let length = 0 ;
427431 if ( ( statFields [ 1 /* mode */ ] & S_IFMT ) === S_IFREG ) {
428432 size = statFields [ 8 /* size */ ] ;
429- } else {
430- size = 0 ;
433+ length = encoding ? MathMin ( size , kReadFileBufferLength ) : size ;
434+ }
435+ if ( length === 0 ) {
436+ length = kReadFileUnknownBufferLength ;
431437 }
432438
433439 if ( size > kIoMaxLength )
434440 throw new ERR_FS_FILE_TOO_LARGE ( size ) ;
435441
436- let endOfFile = false ;
437442 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 ) {
442450 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 ) {
453453 length = MathMin ( size - totalRead , kReadFileBufferLength ) ;
454454 }
455455
456456 const bytesRead = ( await binding . read ( filehandle . fd , buffer , offset ,
457- length , - 1 , kUsePromises ) ) || 0 ;
457+ length , - 1 , kUsePromises ) ) ?? 0 ;
458458 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 ;
464484 }
465- } while ( ! endOfFile ) ;
466485
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+ }
473496 }
474-
475- return options . encoding ? result . toString ( options . encoding ) : result ;
476497}
477498
478499// All of the functions are defined as async in order to ensure that errors
0 commit comments