Getting File Information with Node.js fs Module
Tags: javascript, node, webdev, tutorial
Published: 2020-01-05 22:09:57

Manipulating files and directories are basic operations for any program. Since [Node.js](https://nodejs.org/) is a server-side platform and can interact with the computer that it’s running on directly, being able to manipulate files is a basic feature.

Fortunately, Node.js has an `fs` module built into its library. It has many functions that can help with manipulating files and folders. File and directory operations that are supported include basic ones like manipulating and opening files in directories.

Likewise, it can do the same for files. It can do this both synchronously and asynchronously. It has an asynchronous API that has functions that support promises. Also, it can show statistics for a file.

Almost all the file operations that we can think of can be done with the built-in `fs` module.

In this article, we will use the functions in the `fs` module to get data about a file located in the `fs.Stats` object with the `fs.stat()`, `fs.lstat()`, and `fs.fstat()` functions.

To get information about a file, we can use the `fs.Stats` object, which is returned by the `fs.stat()`, `fs.lstat()`, and `fs.fstat()` functions, and their synchronous counterparts.

They can display numeric data as `bigint` as it’s passed in as an option key with its value set to `true`. It has nanosecond-precision properties suffixed with `Ns`.

The `stat` function takes a path object which can be a string, Buffer, or a URL object as the first argument.

A second argument is an object that can take the `bigint` as the key, which is a boolean value. If it’s set to `true`, then numerical information will be returned as `bigInts`.

The third argument is a callback function that has the error object for the first parameter and the `stats` object as the second parameter, which has the information about a file and it’s running when the file information is retrieved.

The `stat` function runs asynchronously. Its synchronous counterpart is the `statSync` function, which takes the same first two arguments without the callback function. `statSync` returns the file information as an object.

`lstat` is similar to `stat`, but it doesn’t follow the symbolic link. It takes a path object which can be a string, Buffer, or a URL object as the first argument.

A second argument is an object which can take the `bigint` as the key, which is a boolean value. If it’s set to `true`, then numerical information will be returned as `bigInts`.

The third argument is a callback function that has the error object for the first parameter and the `stats` object as the second parameter, which has the information about a file and it’s running when the file information is retrieved.

When the path that’s passed in is a symbolic link, then it gives the information about the symbolic link. `lstat` runs asynchronously, so that the data is retrieved in an indeterminate amount of time.

Its synchronous counterpart, the `lstatSync` function, takes the same arguments as the `lstat` function without the callback function and returns the `Stat` object which has the file information.

The `fstat` function is similar to the `stat` function. It takes a path object which can be a string, Buffer, or an URL object as the first argument.

The second argument is an object which can take the `bigint` as the key, which is a boolean value. If it’s set to `true`, then numerical information will be returned as `bigInts`.

The third argument is a callback function that has the error object for the first parameter and the `stats` object as the second parameter, which has the information about a file and it’s running when the file information is retrieved.

The **only difference** between `stat` and `fstat` is that it takes a file descriptor instead of a path object.

We can get the file descriptor from the callback that's accepted by the `fs.open` function and its promise and synchronous counterparts, `fsPromises.open`, and `fs.opensync`.

To use the `fs.stat` function, we can use it like in the following code:

```javascript
const fs = require("fs");
fs.stat("./files/file.txt", (err, stat) => {  
  if (err) throw err;  
  console.log(stat);  
});
```

Then, if we run the code above, we get something like the following output:

```bash
Stats {  
  dev: 3605029386,  
  mode: 33206,  
  nlink: 1,  
  uid: 0,  
  gid: 0,  
  rdev: 0,  
  blksize: 4096,  
  ino: 22799473115106240,  
  size: 0,  
  blocks: 0,  
  atimeMs: 1572569358035.625,  
  mtimeMs: 1572569358035.625,  
  ctimeMs: 1572569358035.625,  
  birthtimeMs: 1572569358035.625,  
  atime: 2019-11-01T00:49:18.036Z,  
  mtime: 2019-11-01T00:49:18.036Z,  
  ctime: 2019-11-01T00:49:18.036Z,  
  birthtime: 2019-11-01T00:49:18.036Z  
}
```

As we can see, the `Stats` object has many properties. The data properties are listed above. It also has a few function properties.

The data properties in the `Stats` object means the following:

*   `dev` — The numeric identifier of the device storing the given file. It can be a number or a `bigInt`.
*   `ino` — The “inode” number of the file. It’s a number that contains basic information about a file, directory, or other file system object. It can be a number or a `bigInt`.
*   `mode` — Bit-field description of the file type and mode. It can be a number or a `bigInt`.
*   `nlink` — Number of hard links that exist for the file. It can be a number or a `bigInt`.
*   `uid` — The numeric user identifier of the user that owns the file. Applicable to POSIX systems only. It can be a number or a `bigInt`.
*   `gid` — The numeric group identifier of the user that owns the file. Applicable to POSIX systems only. It can be a number or a `bigInt`.
*   `rdev` — Numeric device identifier of the file if it’s a special file. A file is special if it’s used for I/O. For example, page files and hibernation files are considered special files. It can be a number or a `bigInt`.
*   `size` — The size of the file in bytes. It can be a number or a `bigInt`.
*   `blksize` — The block size for a file system I/O. It can be a number or a `bigInt`.
*   `blocks` — The number of blocks allocated to the file. It can be a number or a `bigInt`.
*   `atimeNs` — The timestamp indicating when the file was last accessed in nanoseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `mtimeNs` — The timestamp indicating when the file was last modified in nanoseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `ctimeNs` — The timestamp indicating when the file was last changed in nanoseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `birthtimeNs` — The timestamp indicating when the file was created in nanoseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `atime` — The timestamp indicating when the file was last accessed in milliseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `mtime` — The timestamp indicating when the file was last modified in milliseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `ctime` — The timestamp indicating when the file was last changed in milliseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.
*   `birthtime` — The timestamp indicating when the file was created in milliseconds since the POSIX Epoch, which is the time relative to January 1, 1970 midnight. It can be a number or a `bigInt`.

The `Stats` object also has the following function properties to check for the basic information about a file:

*   `isBlockDevice()` — This is a function with a boolean return value that returns `true` if the file is a block device. A block device refers to a file that represents the device that stores files in blocks and also retrieves them as such.
*   `isCharacterDevice()` — This is a function with a boolean return value that returns `true` if the file is a character device. A character device refers to a file that represents the device that provided unbuffered, direct access to the hardware device. They don’t have to allow programs to read or write a single character at a time.
*   `isDirectory()` — This is a function with a boolean return value that returns `true` if the item is a directory.
*   `isFIFO()` — This is a function with a boolean return value that returns `true` if the item is a first-in-first-out pipe. FIFO pipe means that the first bits of a file going into the device will be the same ones that come out when retrieved. It only allows for unidirectional communication.
*   `isFile()` — This is a function with a boolean return value that returns `true` if the item is a file.
*   `isSocket()` — This is a function with a boolean return value that returns `true` if the item is a socket. A socket is a special file that enables communication between two processes. It can send data and file descriptors across a domain socket. It can do bidirectional communication.
*   `isSymbolicLink()` — This is a function with a boolean return value that returns `true` if the item is a symbolic link. A symbolic link is a reference to another file or directory in the form of an absolute or relative path.

To use the synchronous version of the `stat` function, the `statSync` function, we can write something like the following code:

```javascript
const fs = require("fs");
const stat = fs.statSync("./files/file.txt");  
console.log(stat);
```

The `Stat` object is returned directly from the `statSync` function.

To use the `fstat` function, we have to get the file descriptor first, which we can do with the `open` function and its variants. For example, if we want to use the `open` function to get the file descriptor, we can write the following:

```javascript
const fs = require("fs");
fs.open("./files/file.txt", "r", (err, fd) => {  
  if (err) throw err;  
  fs.fstat(fd, (err, stat) => {  
    if (err) throw err;  
    console.log(stat);  
    fs.close(fd, err => {  
      if (err) throw err;  
    });  
  });  
});
```

We can use `fstat` with the promise version of the `open` function like in the following code:

```javascript
const fsPromises = require("fs").promises;  
const fs = require("fs");
(async () => {  
  const fdObj = await fsPromises.open("./files/file.txt", "r");  
  fs.fstat(fdObj.fd, (err, stat) => {  
    if (err) throw err;  
    console.log(stat);  
    fs.close(fdObj.fd, err => {  
      if (err) throw err;  
    });  
  });  
})();
```

The promise version of the `open` function returns a promise that resolves to an object with the file descriptor inside it. We can use the `fd` property to get the file descriptor and pass it into the `fstat` function.

Likewise, with the `lstat` function, we can call it as in the following code:

```javascript
const fs = require("fs");
fs.lstat("./files/file.txt", (err, stat) => {  
  if (err) throw err;  
  console.log(stat);  
});
```

The `lstat` does almost everything as `stat` does, except that it gets the data of a symbolic link instead of following it, so we will get output similar to the ones above.

The `fs.stat()`, `fs.lstat()`, and `fs.fstat()` functions are very useful for getting data about files, directories, and symbolic links.

They can get us the `Stat` object which has lots of information that we can use, including access time, modified time, whether the file is a special file, the device it’s stored on, and many other pieces of information through its value and function properties.

Data can be displayed as numbers or `bigInt` if they’re numerical and timestamps are available in both milliseconds and nanoseconds for extra precision.