🌍 NodeJS · subject

NodeJS File System Syllabus

The File System syllabus for NodeJS in full: 2 chapters and 5 topics, every one listed below, plus 50 File System flashcards with answers.

2Chapters
5Topics
50Flashcards

File System syllabus: all 2 chapters

Expand any chapter to see its topics and sub-topics.

  1. Reading and Writing Files

    3 topics
    • Synchronous vs Asynchronous
    • Streams
    • Buffers
  2. Directory Operations

    2 topics
    • Creating and Deleting Directories
    • Reading Directory Contents

NodeJS File System flashcards — 50 questions with answers

  1. In Node.js, which core module provides the API for interacting with the file system?

    The `fs` module, imported with `const fs = require('fs')` (or `import fs from 'fs'`). It offers synchronous, callback-based asynchronous, and Promise-based APIs.

  2. What is the fundamental difference between synchronous and asynchronous file system methods in Node.js?

    Synchronous methods block the event loop until the operation completes and return the result directly (or throw). Asynchronous methods return immediately and deliver the result later via a callback, Promise, or event, keeping the event loop free.

  3. How are synchronous `fs` methods named by convention, and give an example?

    They end with the `Sync` suffix, e.g. `fs.readFileSync()`, `fs.writeFileSync()`, `fs.mkdirSync()`. Non-suffixed names like `fs.readFile()` are asynchronous.

  4. How do you read a file synchronously and get its contents as a UTF-8 string?

    `const data = fs.readFileSync('file.txt', 'utf8');` The encoding argument makes it return a string; without it, a `Buffer` is returned.

  5. How do you read a file asynchronously using the classic callback API?

    `fs.readFile('file.txt', 'utf8', (err, data) => { if (err) throw err; console.log(data); });` The error-first callback receives `err` as its first argument.

  6. What is the "error-first callback" convention in Node.js asynchronous APIs?

    The callback's first parameter is reserved for an error object (`null` if none), and subsequent parameters hold the successful result, e.g. `(err, data) => {}`.

  7. How do you use the Promise-based `fs` API to read a file asynchronously?

    Import `const fs = require('fs/promises');` (or `fs.promises`), then `const data = await fs.readFile('file.txt', 'utf8');` inside an `async` function.

  8. Why are synchronous `fs` calls generally discouraged in server code?

    They block the single-threaded event loop, so no other requests or timers can be processed until the operation finishes, harming throughput and responsiveness under load.

  9. When is it acceptable to use synchronous `fs` methods?

    During startup/initialization (e.g. loading config), in CLI scripts, or one-off tooling where blocking is harmless and simpler code is preferable to concurrency.

  10. How do you catch errors from synchronous vs asynchronous `fs` operations?

    Synchronous: wrap in `try/catch` since they throw. Callback async: check the `err` argument. Promise async: use `.catch()` or `try/catch` with `await`.

  11. What does `fs.writeFileSync('out.txt', 'hello')` do if the file already exists?

    It overwrites (truncates and replaces) the file's contents with the new data. To append instead, use `fs.appendFileSync()` or the `{ flag: 'a' }` option.

  12. What is a Stream in Node.js?

    An abstract interface for working with streaming data, processing it in small chunks over time rather than loading the whole payload into memory at once. Streams are instances of `EventEmitter`.

  13. What are the four fundamental types of streams in Node.js?

    Readable (data can be read from it), Writable (data can be written to it), Duplex (both readable and writable), and Transform (a duplex stream that modifies data as it passes through).

  14. Give a real example of each stream type: Readable, Writable, Duplex, Transform.

    Readable: `fs.createReadStream()`. Writable: `fs.createWriteStream()`. Duplex: a TCP socket (`net.Socket`). Transform: `zlib.createGzip()` compression.

  15. How do you create a readable stream from a file?

    `const rs = fs.createReadStream('file.txt', { encoding: 'utf8', highWaterMark: 64 * 1024 });` then listen for `'data'`, `'end'`, and `'error'` events.

  16. What key events does a Readable stream emit?

    `'data'` (a chunk is available in flowing mode), `'end'` (no more data), `'error'` (a problem occurred), `'close'`, and `'readable'` (data is available to read in paused mode).

  17. What key events does a Writable stream emit?

    `'drain'` (the buffer emptied and it's safe to write again after backpressure), `'finish'` (all data flushed after `end()`), `'error'`, and `'close'`, plus `'pipe'`/`'unpipe'`.

  18. What is the purpose of `stream.pipe()`?

    It connects a Readable stream's output to a Writable stream's input, automatically forwarding data chunks and managing backpressure, e.g. `readStream.pipe(writeStream);`.

  19. What is backpressure in Node.js streams?

    A flow-control mechanism where a slow Writable consumer signals a fast Readable producer to pause. `write()` returning `false` indicates the internal buffer is full; the producer waits for the `'drain'` event before resuming.

  20. What does the `highWaterMark` option control on a stream?

    The buffer size threshold (in bytes for binary, or number of objects in object mode) that triggers backpressure. It defaults to 64 KiB ($64 \times 1024 = 65536$ bytes) for file streams and 16 KiB for others.

Show the other 30 File System flashcards
  1. Why is `stream.pipeline()` preferred over `pipe()` for chaining streams?

    `pipeline()` (from the `stream` module) properly propagates errors and automatically destroys/cleans up all streams on failure, whereas manual `pipe()` chains can leak resources and swallow errors.

  2. What is the main memory advantage of streaming a large file versus `fs.readFile()`?

    Streaming holds only one small chunk (~`highWaterMark`) in memory at a time, so memory use is roughly constant, whereas `readFile` loads the entire file into memory, which can exhaust RAM for large files.

  3. What are the two reading modes of a Readable stream?

    Flowing mode (data is pushed automatically via `'data'` events) and paused mode (data is pulled explicitly by calling `stream.read()`). Attaching a `'data'` listener or calling `pipe()` switches it to flowing mode.

  4. What is a Buffer in Node.js?

    A fixed-length, raw binary data container representing a region of memory outside the V8 heap. It stores a sequence of bytes (integers $0$–$255$) and is used for handling binary data like file contents, TCP streams, and images.

  5. Why do Buffers exist given that JavaScript has strings?

    JavaScript strings only handle text (UTF-16), while I/O often deals with raw binary data. Buffers let Node manipulate bytes directly, independent of character encoding.

  6. What is the modern, safe way to allocate a Buffer of a given size, and how does it differ from the alternative?

    `Buffer.alloc(size)` allocates and zero-fills the memory (safe). `Buffer.allocUnsafe(size)` is faster but may contain old, sensitive data until overwritten because it skips zero-filling.

  7. How do you create a Buffer from an existing string?

    `Buffer.from('hello', 'utf8')`. You can also create one from an array of bytes: `Buffer.from([0x68, 0x69])`.

  8. How is the byte length of a Buffer determined, and does it always equal string length?

    Via the `buf.length` property (bytes allocated). It does not always equal the string's character count because multibyte UTF-8 characters occupy more than one byte, e.g. 'é' is $2$ bytes.

  9. Why is the `Buffer` constructor `new Buffer()` deprecated?

    It was ambiguous and unsafe: its behavior depended on argument type, and numeric arguments produced uninitialized memory. It's replaced by `Buffer.alloc()`, `Buffer.allocUnsafe()`, and `Buffer.from()`.

  10. How do you convert a Buffer back into a string with a chosen encoding?

    `buf.toString('utf8')` (or `'hex'`, `'base64'`, `'ascii'`, `'latin1'`). Optional start/end arguments select a byte range.

  11. Which encodings are commonly supported by Node.js Buffers?

    `'utf8'`, `'utf16le'` (`'ucs2'`), `'latin1'` (`'binary'`), `'ascii'`, `'base64'`, `'base64url'`, and `'hex'`.

  12. Are Buffers resizable after creation?

    No. A Buffer has a fixed length set at allocation. To "grow" it you must allocate a new, larger Buffer and copy the data (e.g. via `Buffer.concat()`).

  13. How do you concatenate multiple Buffers into one?

    `Buffer.concat([buf1, buf2, ...])`, optionally passing a total length as the second argument for efficiency.

  14. How do you create a new directory synchronously?

    `fs.mkdirSync('newdir')`. Asynchronously: `fs.mkdir('newdir', callback)` or `await fs.promises.mkdir('newdir')`.

  15. How do you create nested directories (parents that don't yet exist) in one call?

    Pass the `recursive: true` option: `fs.mkdirSync('a/b/c', { recursive: true });`. Without it, creating a directory whose parent is missing throws `ENOENT`.

  16. What error occurs if you call `fs.mkdir` on a directory that already exists (without recursive)?

    An `EEXIST` error. With `{ recursive: true }`, an existing target does not throw.

  17. How do you delete an empty directory?

    `fs.rmdirSync('dir')` or async `fs.rmdir('dir', callback)`. It fails with `ENOTEMPTY` if the directory contains files.

  18. How do you delete a directory and all of its contents recursively (modern API)?

    `fs.rmSync('dir', { recursive: true, force: true });` (or the async `fs.rm`). `force: true` ignores errors if the path doesn't exist. `fs.rmdir` with `recursive` is deprecated in favor of `fs.rm`.

  19. What does the `force: true` option do in `fs.rm()`?

    It suppresses errors when the target path does not exist (no `ENOENT` thrown) and, combined with `recursive`, allows removing non-empty directories quietly.

  20. How do you delete a single file (not a directory) in Node.js?

    `fs.unlinkSync('file.txt')` or async `fs.unlink('file.txt', callback)`. `unlink` is for files; `rmdir`/`rm` handle directories.

  21. How do you create a temporary directory with a unique name?

    `fs.mkdtempSync(prefix)`, e.g. `fs.mkdtempSync(path.join(os.tmpdir(), 'app-'))`, which appends six random characters and returns the created path.

  22. How do you read the contents (entries) of a directory synchronously?

    `const entries = fs.readdirSync('dir');` returns an array of the file and subdirectory names (strings) contained in `dir`.

  23. How do you read directory contents asynchronously with Promises?

    `const entries = await fs.promises.readdir('dir');` inside an `async` function, returning an array of entry names.

  24. What does the `{ withFileTypes: true }` option do for `fs.readdir`?

    It returns an array of `fs.Dirent` objects instead of plain name strings, letting you call `dirent.isDirectory()` or `dirent.isFile()` without a separate `stat` call.

  25. How can you list a directory tree recursively with a single `fs.readdir` call?

    Pass `{ recursive: true }` (Node 18.17+): `fs.readdirSync('dir', { recursive: true })` returns all nested entries' relative paths.

  26. How do you distinguish files from subdirectories when listing a directory?

    Use `fs.statSync(path)` (or `lstatSync`) and check `stats.isFile()` / `stats.isDirectory()`, or use `readdir` with `{ withFileTypes: true }` and check each `Dirent`'s `isFile()`/`isDirectory()`.

  27. What is the difference between `fs.stat` and `fs.lstat`?

    `fs.stat` follows symbolic links and reports info about the target file. `fs.lstat` reports info about the symlink itself without following it.

  28. Which module should you use to build cross-platform file paths when reading directories, and why?

    The `path` module (e.g. `path.join(dir, name)`), because it uses the correct OS-specific separator (`/` vs `\`) and normalizes the result, avoiding manual string concatenation bugs.

  29. What does `fs.existsSync(path)` return, and why is `fs.exists` (callback) deprecated?

    `fs.existsSync` returns a boolean indicating whether the path exists. The callback `fs.exists` is deprecated because its callback signature (single boolean, no error) is inconsistent with Node's error-first convention and invites race conditions.

  30. What comparison summarizes callback-based vs Promise-based async `fs` APIs?

    Both are non-blocking. Callback API (`require('fs')`) uses error-first callbacks and can lead to nested "callback hell." Promise API (`require('fs/promises')`) supports `async/await`, cleaner chaining, and `try/catch` error handling.

NodeJS File System FAQ

What is in the NodeJS File System syllabus?

NodeJS File System is split into 2 chapters: Reading and Writing Files and Directory Operations. Together they contain 5 topics.

How many chapters are in NodeJS File System?

2 chapters, containing 5 topics. The largest chapter is Reading and Writing Files, with 3 topics.

Are there flashcards for NodeJS File System?

Yes — a 50-card File System deck, printed in full in the flashcards section of this page and available in the Examius app with spaced repetition. The free plan covers one exam of your choice, including its flashcards; Examius Pro, a one-time purchase, unlocks every other exam and deck.