Manipulating files and directories are basic operations for any program. Since Node.js 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 a 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 create symbolic links with the symlink
family of functions and set timestamps with the utimes
family of functions.
Creating Symbolic Links
Symbolic links are files that reference other files in the form of relative or absolute paths of the file. We can create symbolic links in Node.js programs with the symlink
function.
The function takes 4 arguments.
The first argument is the target path for our symbolic link which is the file path that we want to reference in our symbolic link. It can be in the form of a string, a buffer object, or an URL object.
The second argument is the path of the symbolic link, it can also be in the form of a string, a buffer object, or an URL object.
The third argument is the type, which is a string. It’s only available on Windows and ignored on other platforms. The possible values are 'dir'
, 'file'
, or 'junction'
.
If the type argument isn’t set, it will automatically detect the type of the target and use 'file'
or 'dir'
. If the target doesn’t exist, then 'file'
would be used. Windows requires that the symbolic link path to be absolute. When using 'junction'
, the target argument will be converted to the absolute path.
The last argument is a callback function that’s called when the symbolic link creation operation ends. It has an err
parameter which is null
when the operation succeeds and has an object with the error information when it failed.
We can create a symbolic link with the symlink
function as follows:
const fs = require("fs");
const target = "./files/file.txt";
const path = "./files/symlink";
fs.symlink(target, path, "file", err => {
if (err) {
throw err;
}
console.log("Symbolic link creation complete!");
});
After running the code above, when we run stat ./files/symlink
on POSIX systems, we should get output that looks something like the following:
File: './files/symlink' -> './files/file.txt'
Size: 16 Blocks: 0 IO Block: 512 symbolic link
Device: eh/14d Inode: 62487444831945583 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 1000/hauyeung) Gid: ( 1000/hauyeung)
Access: 2019-11-03 11:22:19.787359800 -0800
Modify: 2019-11-03 11:22:19.787359800 -0800
Change: 2019-11-03 11:22:19.787359800 -0800
Birth: -
This means that are symbolic link has been successfully created.
There’s also a synchronous version of the symlink
function that’s called the symlinkSync
function. It takes 3 arguments.
The first argument is the target path for our symbolic link which is the file path that we want to reference in our symbolic link. It can be in the form of a string, a buffer object, or an URL object.
The second argument is the path of the symbolic link, it can also be in the form of a string, a buffer object, or an URL object. The third argument is the type, which is a string. It’s only available on Windows and ignored on other platforms.
The possible values are 'dir'
, 'file'
, or 'junction'
. If the type argument isn’t set, it will automatically detect the type of the target and use 'file'
or 'dir'
. If the target doesn’t exist, then 'file'
would be used. Windows requires that the symbolic link path to be absolute.
When using 'junction'
, the target argument will be converted to the absolute path. It returns undefined
.
We can use it to create symbolic links like in the following code:
const fs = require("fs");
const target = "./files/file.txt";
const path = "./files/symlink";
try {
fs.symlinkSync(target, path, "file");
console.log("Symbolic link creation complete!");
} catch (error) {
console.error(error);
}
After running the code above, when we run stat ./files/symlink
on POSIX systems, we should get output that looks the same as the ones above.
There’s also a promise version of the symlink
function. It takes 3 arguments.
The first argument is the target path for our symbolic link which is the file path that we want to reference in our symbolic link. It can be in the form of a string, a buffer object, or an URL object.
The second argument is the path of the symbolic link, it can also be in the form of a string, a buffer object, or an URL object.
The third argument is the type, which is a string. It’s only available on Windows and ignored on other platforms.
The possible values are 'dir'
, 'file'
, or 'junction'
. If the type argument isn’t set, it will automatically detect type of the target and use 'file'
or 'dir'
. If the target doesn’t exist, then 'file'
would be used.
Windows requires that the symbolic link path be absolute. When using 'junction'
, the target argument will be converted to the absolute path. It returns a promise that resolves with no arguments when it’s successful.
We can use it to create symbolic links like in the following code:
const fsPromises = require("fs").promises;
const target = "./files/file.txt";
const path = "./files/symlink";
(async () => {
try {
await fsPromises.symlink(target, path, "file");
console.log("Symbolic link creation complete!");
} catch (error) {
console.error(error);
}
})();
After running the code above, when we run stat ./files/symlink
on POSIX systems, we should get output that looks the same as the ones above.
The promise version of the symlink
function is a much better choice than the symlinkSync
function when you want to do multiple things sequentially that includes a call to the symlink
function since it doesn’t tie up the whole program waiting for the symbolic link creation operation to complete before continuing to program other parts of the program.
Changing Timestamps of Items Stored on Disk
We can change the timestamp of the last accessed time and the last time a file was modified with the utimes
function.
The function takes 4 arguments.
The first is the path of the object stored on disk. It can be a string, a Buffer object, and an URL object.
The second argument is the atime
which is the time that the object was last accessed. It can be a number, a string or a Date object.
If it’s a number, then it should be the UNIX timestamp.
If it’s a string, then it should be a string form of the UNIX timestamp.
If the value can’t be converted to a number or is NaN
, Infinity
or -Infinity
then an error will be thrown.
The third argument is the mtime
, which is the time that the object was last modified. It can be a number, a string or a Date object. It should be in the same format as the atime
argument.
The fourth argument is a callback function which takes an err
parameter. It’s null
when the operation succeeds and has an object that has the error information if it fails.
We can use the utimes
function like in the following code:
const fs = require("fs");
const path = "./files/file.txt";
fs.utimes(
path,
new Date(2019, 0, 1, 0, 0, 0, 0),
new Date(2019, 0, 1, 0, 0, 0, 0),
err => {
if (err) {
throw err;
}
console.log("Timestamps changed");
}
);
If we run the code above then run stat ./files/file.txt
, we should get something like the following output:
File: './files/file.txt'
Size: 16 Blocks: 0 IO Block: 512 regular file
Device: eh/14d Inode: 22799473115106242 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 1000/hauyeung) Gid: ( 1000/hauyeung)
Access: 2019-01-01 00:00:00.000000000 -0800
Modify: 2019-01-01 00:00:00.000000000 -0800
Change: 2019-11-03 11:41:16.155815100 -0800
Birth: -
As we can see, the Access
and Modify
times changed to 2019–01–01 00:00:00.000000000
, so we know that the utimes
function has changed the timestamps successfully.
There’s a synchronous version of the utimes
function called the utimesSync
function.
The function takes 3 arguments.
The first is the path of the object stored on disk. It can be a string, a Buffer object and an URL object. The second argument is the atime
which is the time that the object was last accessed.
It can be a number, a string or a Date object. If it’s a number, then it should be the UNIX timestamp. If it’s a string, then it should be a string form of the UNIX timestamp. If the value can’t be converted to a number or is NaN
, Infinity
or -Infinity
then an error will be thrown.
The third argument is the mtime
, which is the time that the object was last modified. It can be a number, a string or a Date object. It should be in the same format as the atime
argument.
We can use it as in the following code:
const fs = require("fs");
const path = "./files/file.txt";
try {
fs.utimesSync(
path,
new Date(2019, 0, 1, 0, 0, 0, 0),
new Date(2019, 0, 1, 0, 0, 0, 0)
);
console.log("Timestamps changed");
} catch (error) {
console.error(error);
}
If we run the code above then run stat ./files/file.txt
, we should get the same output as we did above.
There’s also a promise version of the utimes
function, which let us run utimes
asynchronously while running it in sequence like we do with the utimesSync
function.
The function takes 3 arguments. The first is the path of the object stored on disk. It can be a string, a Buffer object, and an URL object.
The second argument is the atime
which is the time that the object was last accessed. It can be a number, a string or a Date object. If it’s a number, then it should be the UNIX timestamp.
If it’s a string, then it should be a string form of the UNIX timestamp. If the value can’t be converted to a number or is NaN
, Infinity
or -Infinity
then an error will be thrown.
The third argument is the mtime
, which is the time that the object was last modified. It can be a number, a string or a Date object. It should be in the same format as the atime
argument.
We can use it as in the following code:
const fsPromises = require("fs").promises;
const path = "./files/file.txt";
(async () => {
try {
await fsPromises.utimes(
path,
new Date(2019, 0, 1, 0, 0, 0, 0),
new Date(2019, 0, 1, 0, 0, 0, 0)
);
console.log("Timestamps changed");
} catch (error) {
console.error(error);
}
})();
If we run the code above then run stat ./files/file.txt
, we should also get the same output as the regular utimes
example.
We can create symbolic links with the symlink
family of functions.
It takes 3 arguments. The first is the path of the object stored on disk. It can be a string, a Buffer object, and an URL object.
The second argument is the atime
which is the time that the object was last accessed. It can be a number, a string or a Date object. If it’s a number, then it should be the UNIX timestamp, and if it’s a string, then it should be a string form of the UNIX timestamp.
The regular asynchronous version also takes a callback function which runs when it ends. The utimes
function changes the timestamp of the access and modified time of an object stored on disk. It takes the path of the entity to apply the change and timestamps for access and modified times.
The regular asynchronous version also takes a callback function which runs when it ends. They are handy for times when we need to do these operations in our Node.js programs.