(
filePath: string,
offset = 0,
maxLines?: number,
maxBytes?: number,
signal?: AbortSignal,
options?: { truncateOnByteLimit?: boolean },
)
| 71 | // --------------------------------------------------------------------------- |
| 72 | |
| 73 | export async function readFileInRange( |
| 74 | filePath: string, |
| 75 | offset = 0, |
| 76 | maxLines?: number, |
| 77 | maxBytes?: number, |
| 78 | signal?: AbortSignal, |
| 79 | options?: { truncateOnByteLimit?: boolean }, |
| 80 | ): Promise<ReadFileRangeResult> { |
| 81 | signal?.throwIfAborted() |
| 82 | const truncateOnByteLimit = options?.truncateOnByteLimit ?? false |
| 83 | |
| 84 | // stat to decide the code path and guard against OOM. |
| 85 | // For regular files under 10 MB: readFile + in-memory split (fast). |
| 86 | // Everything else (large files, FIFOs, devices): streaming. |
| 87 | const stats = await fsStat(filePath) |
| 88 | |
| 89 | if (stats.isDirectory()) { |
| 90 | throw new Error( |
| 91 | `EISDIR: illegal operation on a directory, read '${filePath}'`, |
| 92 | ) |
| 93 | } |
| 94 | |
| 95 | if (stats.isFile() && stats.size < FAST_PATH_MAX_SIZE) { |
| 96 | if ( |
| 97 | !truncateOnByteLimit && |
| 98 | maxBytes !== undefined && |
| 99 | stats.size > maxBytes |
| 100 | ) { |
| 101 | throw new FileTooLargeError(stats.size, maxBytes) |
| 102 | } |
| 103 | |
| 104 | // For targeted reads of moderately large files, prefer streaming to |
| 105 | // avoid loading the full file into memory when only a slice is needed. |
| 106 | const isTargetedRead = offset > 0 || maxLines !== undefined |
| 107 | if (isTargetedRead && stats.size > FAST_PATH_MAX_SIZE / 4) { |
| 108 | return readFileInRangeStreaming( |
| 109 | filePath, |
| 110 | offset, |
| 111 | maxLines, |
| 112 | maxBytes, |
| 113 | truncateOnByteLimit, |
| 114 | signal, |
| 115 | ) |
| 116 | } |
| 117 | |
| 118 | const text = await readFile(filePath, { encoding: 'utf8', signal }) |
| 119 | return readFileInRangeFast( |
| 120 | text, |
| 121 | stats.mtimeMs, |
| 122 | offset, |
| 123 | maxLines, |
| 124 | truncateOnByteLimit ? maxBytes : undefined, |
| 125 | ) |
| 126 | } |
| 127 | |
| 128 | return readFileInRangeStreaming( |
| 129 | filePath, |
| 130 | offset, |
no test coverage detected