Skip to content

fs: introduce `opendir()` and `fs.Dir`

This adds long-requested methods for asynchronously interacting and iterating through directory entries by using uv_fs_opendir, uv_fs_readdir, and uv_fs_closedir.

const fs = require('fs');

async function print(path) {
  const dir = await fs.promises.opendir(path);
  for await (const dirent of dir) {
    console.log(dirent.name);
  }
}
print('./').catch(console.error);

fs.opendir() and friends return an fs.Dir, which contains methods for doing reads and cleanup. fs.Dir also has the async iterator symbol exposed.

The read() method and friends only return fs.Dirents for this API. Having a entry type or doing a stat call is deemed to be necessary in the majority of cases, so just returning dirents seems like the logical choice for a new api.

Reading when there are no more entries returns null instead of a dirent. However the async iterator hides that (and does automatic cleanup).

The code lives in separate files from the rest of fs, this is done partially to prevent over-pollution of those (already very large) files, but also in the case of js allows loading into fsPromises.

Due to async_hooks, this introduces a new handle type of DIRHANDLE.

This PR does not attempt to make complete optimization of this feature. Notable future improvements include:

  • Moving promise work into C++ land like FileHandle.
  • Making uv_dir_t keep a record of its path (or a way to retrieve it).
  • Possibly adding readv() to do multi-entry directory reads.
  • Aliasing fs.readdir to fs.scandir and doing a deprecation.

Refs: https://github.com/nodejs/node-v0.x-archive/issues/388 Refs: https://github.com/nodejs/node/issues/583 Refs: https://github.com/libuv/libuv/pull/2057

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

I am open to discussing the api shapes, I found that this fs.Dir api made it easiest to reconcile the callback and promise apis into "one" reasonably nice (hopefully future proof) api, but I feel folks might have strong feelings about that. It does make a bit of mess in the docs though.

Also please tell me any C++ nonsense I got terribly wrong, haha.

Merge request reports

Loading