Description
Problem
Now any interaction with files and directories in the File System is as follows:
const fs = require('fs');
const entries = fs.readdirSync('path_to_directory');
const stats = entries.map(fs.statSync); // Unnecessary File System access
const dirs = [];
const files = [];
entries.forEach((entry, index) => {
if (stats[index].isDirectory()) {
dirs.push(entry);
} else {
files.push(entry);
}
});
The problem here is that we are call File System a second time due to the fact that we don't know the directory in front of us, or file (or symlink).
But we can reduce twice File System calls by creating fs.scandir
method that can return d_name
and d_type
. This information is returned from uv_dirent_t
(scandir
) (libuv). For example, this is implemented in the Luvit
and pyuv
(also use libuv
).
Motivation
- Performance – reduce twice File System calls
- More consistency with other platforms/languages
- Should be easy to implement
String
→Object
→d_name
+d_type
- For
fs.readdir
: return convertedObject
toString
- For
fs.scandir
: return As is
- For
- Early speed up for
node-glob
(also for each package that usesfs.readdir
for traversing directories) in most cases (needfs.stat
whend_type
is aDT_UNKNOWN
on the old FS)
Proposed solution
Add a methods fs.scandir
and fs.scandirSync
in a standard Fyle System module.
const fs = require('fs');
const entries = fs.scandirSync('path_to_directory');
const dirs = [];
const files = [];
entries.forEach((entry) => {
if (entry.type === fs.constants.S_IFDIR) {
dirs.push(entry);
} else {
files.push(entry);
}
});
Where entries
is an array of objects:
name
{String} – filename (d_name
inlibuv
)type
{Number} –fs.constants.S_*
(d_type
inlibuv
)
Final words
Now I solved this problem by creating C++ Addon but... But I don't speak C++ or speak but very bad (i try 😅 ) and it requires you compile when you install a package that requires additional manipulation to the end user (like https://github.com/nodejs/node-gyp#on-windows).