Git Product home page Git Product logo

readdir's Introduction

@folder/readdir Donate NPM version NPM monthly downloads NPM total downloads

Recursively read a directory, blazing fast.

Please consider following this project's author, Jon Schlinkert, and consider starring the project to show your ❤️ and support.

Install

Install with npm (requires Node.js >=10):

$ npm install --save @folder/readdir

Why use @folder/readdir and not some other lib?

Usage

const readdir = require('@folder/readdir');
const options = {};

// async usage
console.log(await readdir('somedir', options));
console.log(await readdir(['two', 'dirs'], options));

// sync usage
console.log(readdir.sync('somedir', options));
console.log(readdir.sync(['two' 'dirs'], options));

params

Both the async and sync functions take the same arguments:

readdir(dir, options);
  • dir (string|array) - one or more directories to read
  • options - see available options

Options

absolute

When true, absolute paths are returned. Otherwise, returned paths are relative to options.base if defined, or the given directory.

Type: boolean

Default: undefined

Example

console.log(await readdir('some/dir', { absolute: true }));

base

The base directory from which relative paths should be created.

Type: string

Default: Defaults to the directory passed as the first argument.

Example

const files = await readdir('some/dir', { base: 'dir' });
console.log(files);

basename

When true, only the basename of each file is returned.

Type: boolean

Default: undefined

Example

console.log(await readdir('some/dir', { basename: true }));

depth

The maximum folder depth to recursively read directories.

Type: number

Default: undefined

Example

const files = await readdir('some/dir', { depth: 2 });
console.log(files);

dot

Dotfiles are included in the result by default. Pass false to ignore all dotfiles. Use [onEach][], [onFile][], [onDirectory][], or [isMatch] if you need something more granular.

Type: boolean

Default: true

Example

const files = await readdir('.');
console.log(files);
//=> ['.DS_Store', '.git', 'LICENSE', 'README.md', 'package.json']

const files = await readdir('.', { dot: false });
console.log(files);
//=> ['LICENSE', 'README.md', 'package.json']

filter

Type: function|string|array|regexp

Default: undefined

Example

// only return file paths with "foo" somewhere in the path
console.log(await readdir('some/dir', { filter: /foo/ }));

// only return file paths without "foo" somewhere in the path
console.log(await readdir('some/dir', { filter: file => !/foo/.test(file.path) }));

follow

Follow symbolic links.

Type: boolean

Default: undefined

Example

console.log(await readdir('some/dir', { follow: true }));

isMatch

Type: function|string|regex|array<function|string|regex>

Default: undefined

Example

// only return file paths with "/.git/" somewhere in the path
console.log(await readdir('some/dir', { isMatch: /\/\.git\// }));

// only return file paths that are not inside "node_modules"
console.log(await readdir('some/dir', { isMatch: file => !file.relative.includes('node_modules') }));

// get all files that are not named .DS_Store
console.log(await readdir('some/dir', { isMatch: file => file.name !== '.DS_Store' }));

// use globs
const picomatch = require('picomatch');
const isMatch = picomatch('*/*.js');
console.log(await readdir('some/dir', { isMatch: file => isMatch(file.relative) }));

nodir

When true directories are excluded from the result.

Type: boolean

Default: undefined

objects

Return fs.Dirent objects instead of paths.

Type: boolean

Default: undefined

console.log(await readdir('some/dir', { objects: true }));

onDirectory

Function to be called on all directories.

Type: function

Default: undefined

Example

const onDirectory = file => {
  if (file.name === 'node_modules') {
    file.recurse = false;
  }
};
console.log(await readdir('some/dir', { onDirectory }));

onEach

Function to be called on all directories and files.

Type: function

Default: undefined

Example

const onEach = file => {
  if (file.name === 'node_modules') {
    file.recurse = false;
  }
  if (file.isFile() && file.name[0] === '.') {
    file.keep = true;
  }
};
console.log(await readdir('some/dir', { onEach }));

onFile

Function to be called on all files.

Type: function

Default: undefined

Example

const onFile = file => {
  if (file.isFile() && file.name[0] === '.') {
    file.keep = true;
  }
};
console.log(await readdir('some/dir', { onFile }));

onSymbolicLink

Function to be called on all symbolic links.

Type: function

Default: undefined

Example

const onSymbolicLink = file => {
  // do stuff
};
console.log(await readdir('some/dir', { onSymbolicLink }));

realpath

When true, the realpath of the file is returned in the result. This can be used in combination with other options, like basename or relative.

Type: boolean

Default: undefined

Example

console.log(await readdir('some/dir', { realpath: true }));

recursive

Type: function

Type: string

Type: boolean

Default: undefined

Example

const files = await readdir('some/dir', { recursive: true });
console.log(files);

symlinks

Returns the first directory level of symbolic links. Use options.follow to recursively follow symlinks.

Type: boolean

Default: undefined

Example

console.log(await readdir('some/dir', { symlinks: true }));

unique

Return only unique file paths. Only needed when options.realpath is true.

Type: boolean

Default: undefined

Example

console.log(await readdir('some/dir', { unique: true }));

Tips & Tricks

Use the onFile option to operate on files as they are read from the file system, before they are pushed onto the results array.

This allows you to pricisely control which files are returned.

(Note that even when you specify that files should be returned as paths rather than objects, all functions passed on the options will receive files as objects, so that you may manipulate the paths that are returned however you need to)

const readdir = require('@folder/readdir');
const isMatch = file => true;

module.exports = async (dir, options) => {
  const opts = { absolute: true, recursive: true, objects: true, ...options };
  const files = [];

  const onFile = file => {
    if (isMatch(file)) {
      files.push(file);
    }
  };

  await readdir(dir, { ...opts, onFile });
  return files;
};

Files and directories

The onFile option does not receive dir objects, only dirents (files). If you need both files and directories, you can do the following:

const readdir = require('@folder/readdir');
const isMatch = file => true;

module.exports = async (dir, options) => {
  const opts = { recursive: true, objects: true, ...options };
  const files = [];

  const onDirectory = file => {
    if (file.name === 'node_modules') {
      file.recurse = false;
    }
  };

  const onFile = file => {
    if (isMatch(file)) {
      files.push(file);
    }
  };

  await readdir(dir, { ...opts, onFile, onDirectory });
  return files;
};

Or you can use onEach (which gives you each file before it has been determined whether or not the file will be returned based on other criteria and options. this allows you to override default behavior in a granular way), or onPush (which gives you a file that is going to be returned in the results array).

Here, we only show onEach, since it's identical to onPush in terms of usage.

const readdir = require('@folder/readdir');

const ignore = ['node_modules', '.git'];
const isIgnored = file => ignore.includes(file.nane);

module.exports = async (dir, options) => {
  const opts = { recursive: true, objects: true, ...options };
  const files = [];

  const onEach = file => {
    if (file.isDirectory()) {
      file.recurse = !isIgnored(file);
    } else {
      files.push(file);
    }
  };

  await readdir(dir, { ...opts, onFile, onEach });
  return files;
};

Benchmarks

(Note that only the benchmarks against fdir are included here since that library claims to be the fastest)

To run the benchmarks yourself, you'll need to cd into the bench folder and run $ npm i. Run the recursive-large benchmarks last, and before you run them cd into bench/fixtures and do $ npm i.

Specs

  • CPU: Intel® Core™ i9-9980HK 2.4GHz
  • Cores: 16 (8 Physical)
  • RAM: 64GB
  • Disk: Apple APPLE SSD AP2048N 1864GB NVMe (PCIe x4)
  • OS: macOS macOS Big Sur (darwin)
  • Kernel: 20.3.0 x64
  • Node: v15.14.0
  • V8: 8.6.395.17-node.28
# single directory (~5-10 files)
  @folder/readdir x 24,938 ops/sec (124,693 runs sampled)
             fdir x 24,771 ops/sec (123,858 runs sampled)

# recursive ~220 files
  @folder/readdir x 1,915 ops/sec (9,576 runs sampled)
             fdir x 1,850 ops/sec (9,253 runs sampled)

# recursive ~2,700 files
  @folder/readdir x 155 ops/sec (780 runs sampled)
             fdir x 145 ops/sec (730 runs sampled)

# recursive ~57,200 files (just gatsby!)
  @folder/readdir x 11 ops/sec (57 runs sampled)
             fdir x 10 ops/sec (54 runs sampled)

About

Contributing

Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.

Running Tests

Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:

$ npm install && npm test
Building docs

(This project's readme.md is generated by verb, please don't edit the readme directly. Any changes to the readme must be made in the .verb.md readme template.)

To generate the readme, run the following command:

$ npm install -g verbose/verb#dev verb-generate-readme && verb

Author

Jon Schlinkert

License

Copyright © 2021, Jon Schlinkert. Released under the MIT License.


This file was generated by verb-generate-readme, v0.8.0, on April 19, 2021.

readdir's People

Contributors

jonschlinkert avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

tpenaranda

readdir's Issues

showing dot files by default

if (options.dot === false && file.name.startsWith('.')) return;

should this be || as opposed to && or something else? (in lib/sync as well)

after looking a little further, methinks the previous logic works due to options.dot never being initialized anywhere

if (options.dot !== true && file.name.startsWith('.')) return

btw, this is absolutely awesome!!!!!!!!!!!!!!!!!!!!!!

EPERM: operation not permitted,

Hi,

Running on average windows disk I run in to problems that sometimes access is not allowed or something like that. I am fine with this but I do want the crawl to continue and just log the errors. I couldn't find any solution on how to do this.

UnhandledPromiseRejectionWarning: Error: EPERM: operation not permitted, scandir 'c:\Config.Msi'

I can ofcourse catch this but then still the crawl stops.

Great work here! But your benchmark results are different for my setup

Here are the results I am getting on my system.

First run:

# recursive ~51336 files
             fdir x 651 ops/sec (3,259 runs sampled)
  @folder/readdir x 421 ops/sec (2,106 runs sampled)
 readdir-enhanced x 72 ops/sec (362 runs sampled)
         readdirp x 59 ops/sec (299 runs sampled)
# recursive ~220 files
             fdir x 3,374 ops/sec (16,872 runs sampled)
  @folder/readdir x 2,778 ops/sec (13,891 runs sampled)
 readdir-enhanced x 501 ops/sec (2,508 runs sampled)
         readdirp x 433 ops/sec (2,166 runs sampled)
# single directory (~5-10 files)
             fdir x 39,164 ops/sec (195,824 runs sampled)
  @folder/readdir x 37,425 ops/sec (187,128 runs sampled)
 readdir-enhanced x 28,414 ops/sec (142,073 runs sampled)
         readdirp x 4,410 ops/sec (22,053 runs sampled)

Second run:

# recursive ~1550 files
             fdir x 591 ops/sec (2,957 runs sampled)
  @folder/readdir x 453 ops/sec (2,267 runs sampled)
 readdir-enhanced x 65 ops/sec (328 runs sampled)
         readdirp x 59 ops/sec (296 runs sampled)
# recursive ~220 files
             fdir x 3,173 ops/sec (15,869 runs sampled)
  @folder/readdir x 2,730 ops/sec (13,651 runs sampled)
 readdir-enhanced x 461 ops/sec (2,307 runs sampled)
         readdirp x 426 ops/sec (2,130 runs sampled)
# single directory (~5-10 files)
             fdir x 36,963 ops/sec (184,815 runs sampled)
  @folder/readdir x 37,717 ops/sec (188,586 runs sampled)
 readdir-enhanced x 24,393 ops/sec (121,966 runs sampled)
         readdirp x 4,368 ops/sec (21,843 runs sampled)

You have done some epic work here with your library but creating your own benchmarking library (as tempting as it may be) is probably not the best way to measure performance. Why not use benchmark.js or benny (benny uses benchmark.js) that fdir uses?

Supposing that you made no error (which is very improbable in software) with your benchmark library, the results posted in your README are still not accurate. The only area where @folder/readdir has an edge on fdir is single directory crawling and that too only on some runs.

In any case, you have done amazing work here! Kudos!


My system specs are:

OS: Kubuntu 20.10 x86_64 
Host: GS63VR 7RF REV:1.0 
Kernel: 5.4.111-0504111-generic 
Shell: bash 5.0.17 
DE: Plasma 5.19.5 
WM: KWin 
Terminal: konsole 
CPU: Intel i7-7700HQ (8) @ 3.800GHz 
GPU: NVIDIA GeForce GTX 1060 Mobile 
GPU: Intel HD Graphics 630 
Memory: 6012MiB / 15896MiB 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.