Codepath

Filesystem

Overview

Use the core fs module to perform local filesystem operations.

Note: Each method also has a sync version, which should only be used on the first event loop tick, to avoid blocking the entire process and creating compounding latency across concurrent requests.

Note: Path arguments can be relative to process.cwd() or absolute.

Note: Core APIs use callbacks by default. Since callbacks are a known anti-pattern, all the guides use promises (via songbird) instead. Further, examples are assumed to be contained within the context an async function where await is available.

Example File CRUD

Create

let msg = 'Hello, World!'
await fs.promise.writeFile('helloworld.txt', msg)
console.log('File created')
Using Streams:
let msg = 'Hello, World!'
let stream = fs.createWriteStream('helloworld.txt')
stream.write(msg);
stream.end();

Read

let data = await fs.promise.readFile('helloworld.txt', 'utf8')
console.log(data)
Here we set the encoding to utf8 so the file content returns as a string.

Using Stream:

let readStream = fs.createReadStream('helloworld.txt')
stream.on('data', 'utf8', data => console.log(data))
stream.on('end', () => stream.close())

Update

Updating files is easy because the above methods for creating files automatically overwrite any content if executed with an existing file path. Other methods for updating files include:

Append

Append contents to the end of a file with fs.appendFile:

let msgToAppend = '\nHow are you?'
await fs.promise.appendFile('helloworld.txt', msgToAppend)
console.log('File appended')

Move (Rename)

let oldPath = 'helloworld.txt'
let newPath = 'heyworld.txt'
await fs.promise.rename(oldPath, newPath)
console.log(`${oldPath} renamed ${newPath}`)

Delete

await fs.promise.unlink('helloworld.txt')
console.log('File deleted')

Additional Functionality

fs.stat

Returns a Stats object with meta data including size and last accessed and modified dates. Stats also includes helper methods (e.g., .isFile() and .isDirectory()):

let stat = await fs.promise.stat('foo/bar')
if (stat.isDirectory()) {
  // do work
}

fs.watch

fs.watch (and fs.watchFile) tracks changes made in a given file or directory, and returns a rename or change event:

fs.watch('path/to/file/or/dir', (event, filename) => {
  if (event === 'rename') {
    console.log('File was renamed or deleted')
  } else if (event === 'change') {
    console.log('File was changed')
  }
})

However, fs.watch is well known to be unreliable across different platforms. For example, the filename callback parameter is actually not reported on OSX. Furthermore, often simple changes are reported as rename events.

3rd-Party Packages

rimraf

rimraf is a useful package that allows non-empty directories to be deleted, while fs.unlink does not. It also allows recursive deletion, so be careful not to accidentally erase the file you're working on.

let rimraf = require('rimraf')

// In an async function...
await rimraf.promise('path/to/directory')
console.log('Directory deleted')

chokidar

chokidar is a package that wraps fs.watch and fs.watchFile and effectively resolves their unreliability:

let chokidar = require('chokidar')

let watcher = chokidar.watch('.', {ignored: 'node_modules'})

watcher.on('all', (event, path, stat) => {
  console.log(event, path);
  if (event === 'change') {
    console.log(stat)
  }
})
This example assigns a watcher to the entire current directory ('.'), to register all events, ignoring node_modules/.

add, addDir, change events each return the same stats object as fs.stat above.

Additional files can easily be added to the watcher (in cases when not all files are already being watched) with:

watcher.add('addition.txt')
And removed:
watcher.unwatch('someFile.js')

fs-extra

fs-extra wraps fs to provide additional methods Can be used in place of fs:

let fs = require('fs-extra')

Supported methods: copy, copySync, createOutputStream, emptyDir, emptyDirSync, ensureFile, ensureFileSync, ensureDir, ensureDirSync, mkdirs, mkdirsSync, move, outputFile, outputFileSync, outputJson, outputJsonSync, readJson, readJsonSync, remove, removeSync, writeJson, writeJsonSync

Fork me on GitHub