Skip to content

Commit 83405a7

Browse files
committed
add support for chunked reading in fs/promises
1 parent 9ea02ac commit 83405a7

File tree

3 files changed

+57
-20
lines changed

3 files changed

+57
-20
lines changed

lib/internal/fs/promises.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const {
4545
},
4646
} = require('internal/errors');
4747
const { isArrayBufferView } = require('internal/util/types');
48-
48+
const console = require('internal/console/global');
4949
const {
5050
constants: {
5151
kMaxUserId,
@@ -519,8 +519,17 @@ async function readFileHandle(filehandle, options) {
519519

520520
let size = 0;
521521
let length = 0;
522-
if ((statFields[1/* mode */] & S_IFMT) === S_IFREG) {
523-
size = statFields[8/* size */];
522+
const maxFileSize = 2 ** 31 - 1; // 2 GiB limit for file size
523+
524+
if ((statFields[1 /* mode */] & S_IFMT) === S_IFREG) {
525+
size = statFields[8 /* size */];
526+
527+
if (size > maxFileSize) {
528+
console.warn(
529+
`Warning: File size (${size} bytes) exceeds the supported limit of ${maxFileSize} bytes. Consider using chunked reading.`,
530+
);
531+
}
532+
524533
length = encoding ? MathMin(size, kReadFileBufferLength) : size;
525534
}
526535
if (length === 0) {
@@ -549,9 +558,11 @@ async function readFileHandle(filehandle, options) {
549558
)) ?? 0;
550559
totalRead += bytesRead;
551560

552-
if (bytesRead === 0 ||
553-
totalRead === size ||
554-
(bytesRead !== buffer.length && !chunkedRead && !noSize)) {
561+
if (
562+
bytesRead === 0 ||
563+
totalRead === size ||
564+
(bytesRead !== buffer.length && !chunkedRead && !noSize)
565+
) {
555566
const singleRead = bytesRead === totalRead;
556567

557568
const bytesToCheck = chunkedRead ? totalRead : bytesRead;
@@ -574,9 +585,10 @@ async function readFileHandle(filehandle, options) {
574585
result += decoder.end(buffer);
575586
return result;
576587
}
577-
const readBuffer = bytesRead !== buffer.length ?
578-
buffer.subarray(0, bytesRead) :
579-
buffer;
588+
const readBuffer =
589+
bytesRead !== buffer.length ?
590+
buffer.subarray(0, bytesRead) :
591+
buffer;
580592
if (encoding) {
581593
result += decoder.write(readBuffer);
582594
} else if (size !== 0) {
@@ -590,6 +602,7 @@ async function readFileHandle(filehandle, options) {
590602
}
591603
}
592604

605+
593606
// All of the functions are defined as async in order to ensure that errors
594607
// thrown cause promise rejections rather than being thrown synchronously.
595608
async function access(path, mode = F_OK) {

test/parallel/test-fs-promises-file-handle-readFile.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const fs = require('node:fs');
99
const {
1010
open,
1111
readFile,
12+
truncate,
1213
writeFile,
1314
} = fs.promises;
1415
const path = require('node:path');
@@ -123,6 +124,25 @@ async function doReadAndCancel() {
123124

124125
await fileHandle.close();
125126
}
127+
128+
// For validates the ability of the filesystem module to handle large files
129+
{
130+
const largeFileSize = 5 * 1024 * 1024 * 1024; // 5 GiB
131+
const newFile = path.resolve(tmpDir, 'dogs-running3.txt');
132+
133+
if (!tmpdir.hasEnoughSpace(largeFileSize)) {
134+
common.printSkipMessage(`Not enough space in ${tmpDir}`);
135+
} else {
136+
await writeFile(newFile, Buffer.from('0'));
137+
await truncate(newFile, largeFileSize);
138+
139+
const fileHandle = await open(newFile, 'r');
140+
141+
const data = await fileHandle.readFile();
142+
console.log(`File read successfully, size: ${data.length} bytes`);
143+
await fileHandle.close();
144+
}
145+
}
126146
}
127147

128148
validateReadFile()

test/parallel/test-fs-readfile.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,23 @@ for (const e of fileInfo) {
5757
{
5858
const kLargeFileSize = 3 * 1024 * 1024 * 1024; // 3 GiB
5959

60-
const file = path.join(tmpdir.path, 'temp-large-file.txt');
61-
fs.writeFileSync(file, Buffer.alloc(1024));
62-
fs.truncateSync(file, kLargeFileSize);
60+
if (!tmpdir.hasEnoughSpace(kLargeFileSize)) {
61+
// truncateSync() will fail with ENOSPC if there is not enough space.
62+
common.printSkipMessage(`Not enough space in ${tmpdir.path}`);
63+
} else {
64+
const file = path.join(tmpdir.path, 'temp-large-file.txt');
65+
fs.writeFileSync(file, Buffer.alloc(1024));
66+
fs.truncateSync(file, kLargeFileSize);
6367

64-
fs.readFile(file, (err, data) => {
65-
if (err) {
66-
console.error('Error reading file:', err);
67-
} else {
68-
console.log('File read successfully:', data.length);
69-
}
70-
});
68+
fs.readFile(file, (err, data) => {
69+
if (err) {
70+
console.error('Error reading file:', err);
71+
} else {
72+
console.log('File read successfully:', data.length);
73+
}
74+
});
75+
}
7176
}
72-
7377
{
7478
// Test cancellation, before
7579
const signal = AbortSignal.abort();

0 commit comments

Comments
 (0)