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 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 file operations that we can think of can be done with the built-in fs
module.
In this article, we will change ownership of a file with the chown
function and copy files with the copyFile
function.
Changing File Ownership With the fs.chown and fs.chownSync Functions
The chown
function lets us change the ownership of a file asynchronously. It takes four arguments.
- The first argument is the path object which can be in the form of a string, a
Buffer
object, or a URL object. - The second argument is the UID, which is the user ID of the user.
- The third argument is the GID, which is the group ID.
- The fourth argument is a callback function that has an
err
parameter which isnull
if thechown
operation is successful, otherwiseerr
will be an error object. The callback function is called when thechown
operation is finished, whether it’s successful or not.
To use the chown
function, we can write something like the following code:
In the example above, we change the ownership of the file file.txt
to the user with UID 1000 and group with GID 1000. To find out the UID and GID of the user and group of the current user in Linux systems, we can use the id
command.
The chown
function has a synchronous version called chownSync
. It takes three arguments.
- The first argument is the path object which can be in the form of a string, a
Buffer
object, or a URL object. - The second argument is the UID, which is the user ID of the user.
- The third argument is the GID, which is the group ID. It returns
undefined
.
We can use it as in the following code:
const fs = require("fs");
const file = "./files/file.txt";
fs.chownSync(file, 1000, 1000);
console.log("File ownership changed");
It does the same thing as chown
, but does it synchronously. If we just want to do the chown
operation sequentially, we don’t have to use chown
, a better alternative is to use the promise version of the chown
function.
The promise version of the chown
function takes three arguments.
- The first argument is the path object which can be in the form of a string, a
Buffer
object, or a URL object. - The second argument is the UID, which is the user ID of the user.
- The third argument is the GID, which is the group ID. It returns a promise that resolves with no arguments when the
chown
operation is successfully done.
We can use it as in the following code:
To confirm that the chown
worked as we expected, we can run the following commands in Linux systems. One way is to run ls -l
, as in the command below:
ls -l ./files/file.txt
We can also use the stat
command.
For example, we can run stat ./files/file.txt
to get the ownership information of ./files/file.txt
from the Uid
and Gid
output. With the stat
command, we should get output that looks something like this:
File: './files/file.txt'
Size: 16 Blocks: 0 IO Block: 512 regular file
Device: eh/14d Inode: 22799473115106242 Links: 1
Access: (0555/-r-xr-xr-x) Uid: ( 1000/hauyeung) Gid: ( 1000/hauyeung)
Access: 2019-11-02 12:26:47.996290200 -0700
Modify: 2019-11-02 12:26:47.996290200 -0700
Change: 2019-11-02 12:44:45.037581600 -0700
Birth: -
Also, we can filter out the information we don’t need and just get the UID and GID with the "%U %G"
format sequence. For example, we can run stat -c “%U %G” ./files/file.txt
to get the UID and GID only for file.txt
.
Copy Files With fs.copyFile and fs.copyFileSync
To copy files in a Node.js program, we can use the copyFile
function. The copyfile
function takes four arguments.
- The first argument is the path of the source file, which can be a string, a
Buffer
object, or a URL object. - The second argument is the path of the destination file, which can also be a string, a
Buffer
object, or a URL object. - The third argument is a numeric flag argument that specifies the behavior of the copy operation. The default value of the flag is 0.
The flag can be one of the following values or a bitwise combination of them:
fs.constants.COPYFILE_EXCL
— The copy operation will fail if the destination file already exists.fs.constants.COPYFILE_FICLONE
— The copy operation will attempt to create a copy-on-write reflink. Copy-on-write means that if a file is copied but not modified then it will just reference the original file. The only time that it will do the actual copy is when we first write to a file. If the platform does not support copy-on-write, then a fallback copy mechanism is used.fs.constants.COPYFILE_FICLONE_FORCE
— The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then the operation will fail.
We can combine the constants above with the bitwise OR
operator, for example like fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE
.
4. The fourth argument is a callback function that is called when the file copy operation is complete. It has an err
parameter which is null
when the copy file operation succeeded and an object with the error information otherwise.
There’s no guarantee of the atomicity of the copy operation. If an error occurs after the destination file is opened for writing, then Node.js will attempt to remove the destination.
By default, if no flags are set, the destination file will overwrite the existing file with the same name in the same location if it exists.
To use the copyFile
function, we can write something like the following code:
In the code above, we set the source of the source file to be file.txt
, the destination file to be fileCopy.txt
.
Also, we specified that the copy operation will fail if the file exists with the fs.constants.COPYFILE_EXCL
constant and we specify that the copy file operation will be done via the copy-on-write method with the fs.constants.COPYFILE_FICLONE
flag.
The synchronous version of the copyFile
function is the copyFileSync
function. It takes the same arguments as the copyFile
function except the callback.
- The first argument is the path of the source file, which can be a string, a
Buffer
object, or a URL object. - The second argument is the path of the destination file, which can also be a string, a
Buffer
object, or a URL object. - The third argument is a numeric flag argument that specifies the behavior of the copy operation. The default value of the flag is 0. The flags are the same ones as the
copyFile
function, and we can also combine them the same way.
There’s no guarantee of the atomicity of the copy operation. If an error occurs after the destination file is opened for writing, then Node.js will attempt to remove the destination.
By default, if no flags are set, the destination file will overwrite the existing file with the same name in the same location if it exists.
To use the copyFileSync
function, we can write some code like the following example:
In the code above, we set the source of the source file to be file.txt
, the destination file to be fileCopy.txt
.
Also, we specified that the copy operation will fail if the file exists with the fs.constants.COPYFILE_EXCL
constant and we specify that the copy file operation will be done via the copy-on-write method with the fs.constants.COPYFILE_FICLONE
flag.
We catch any exceptions that are thrown by surrounding the code with the try...catch
block.
There’s also a promise version of the copyFile
function. It asynchronously copies the file from the source to the destination.
- The first argument is the path of the source file, which can be a string, a
Buffer
object, or a URL object. - The second argument is the path of the destination file, which can also be a string, a
Buffer
object, or a URL object. - The third argument is a numeric flag argument that specifies the behavior of the copy operation. The default value of the flag is 0. The flags are the same ones as the
copyFile
function, and we can combine them the same way.
There’s no guarantee of the atomicity of the copy operation. If an error occurs after the destination file is opened for writing, then Node.js will attempt to remove the destination.
By default, if no flags are set, the destination file will overwrite the existing file with the same name in the same location if it exists.
The promise version of copyFile
resolves with no argument if the copy operation is successful.
We can use the promise of copyFile
as in the following code:
In the code above, we set the source of the source file to be file.txt
, the destination file to be fileCopy.txt
.
Also, we specified that the copy operation will fail if the file exists with the fs.constants.COPYFILE_EXCL
constant and we specify that the copy file operation will be done via the copy-on-write method with the fs.constants.COPYFILE_FICLONE
flag.
We catch any exceptions that are thrown by using surround the code with the try...catch
block.
Conclusion
With the chown
function, we can change the ownership of a file. There are two asynchronous versions of the function, one is the regular asynchronous version and one is the promise version.
There’s also one synchronous version of the chown
function, which is the chownSync
function. They both change the owner by passing in the UID and GID of the user of your choice. UID is the user ID and GID is the group ID. We can copy files with the copyFile
function.
There are two asynchronous versions of the copyFile
function, one is the regular asynchronous version and one is the promise version.
There’s also a synchronous version of the copyFile
function called the copyFileSync
function. We can change how files are copied with flags that are available as constants in the fs
module.