By using the carat sign (^), you can tell npm you want versions greater than the
specified version
in the same major range. For instance, ^2.2 shows that you want any version from 2.2 to 3.0 (not
included).
$ npm i {package_name}@^2.2
The tilde sign (~) gives similar functionality as the carat sign, but it includes the range in the
same minor range. For instance, ~2.2 indicates that you want any version from 2.2 to 2.2.x.
$ npm i {package_name}@~2.2
Versions can be combined with double pipe (||) sign to indicate multiple sets of versions:
$ npm i {package_name}@”~2.2 || ~4”
Global packages
Global packages are the ones that got installed in the node_modules folder where your
npm tool’s program is installed. These packages are available through the entirety of your
system. A global package can be installed using the -g flag:
$ npm i {package_name} -g
Caution: Only packages that provide tools or executables should be installed globally. Like
CLI tools. Project-specific packages should be installed locally, so they match the version
they need and avoid conflicts.
npm remove
This command acts exactly the opposite of npm install. By using this command, you can
remove a package:
$ npm remove {package_name}
For instance, if you want to remove the random package, you can run this command:
$ npm remove random
176
This will delete the package from the node_modules folder, but it will still be present as a
dependency in the package.json file. If you want to remove it from there as well, you should use
the –save flag:
$ npm remove random --save
And if you’ve installed this package as a dev dependency, you should use the --save-dev flag to
remove it from the package.json file:
$ npm remove random --save-dev
npm list
This command lists the packages of the current project.
$ npm list
`-- random@2.2.0
+-- babel-runtime@6.26.0
| +-- core-js@2.6.11
| `-- regenerator-runtime@0.11.1
+-- ow@0.4.0
+-- ow-lite@0.0.2
`-- seedrandom@3.0.5
By adding the -g flag, you can list the globally installed packages:
$ npm list -g
177
Chapter 14: File System
One of the essentials of every program is working with files. It can be used to read
information to a file or to write them into a file. As you’ve read before in previous chapters, the
file system of Node.js is functioning thanks to the fs module. It is needed to import the file
system before going any further:
const fs = require('fs')
Now it is possible to access all the methods used to work with files using the fs constant. This
module features two kinds of methods, which are asynchronous and synchronous. The
asynchronous methods take a callback to be called when the operation is done. On the other
hand, synchronous methods (which are suffixed with the Synch keyword) will block the thread
and won’t let Node.js proceed until the operation is finished. Using synchronous methods is
highly discouraged.
File
Read
Reading is a common task done using the file system. This goal can be achieved by using
the readFile or readFileSynch methods. The signature of readFile is as below:
fs.readFile(path[, options], callback)
The first argument is for specifying the path of the file that is to be read, and the optional second
argument is to set the encoding or the flag (file system flags). The callback is to get the data or
the encountered error.
fs.readFile('test.txt', 'utf-8', (err, data) => {
if(err) console.log(err)
else console.log(data)
})
By running the code above, you’ll see the data of the file in the command line or an error as
below if the file doesn’t exist:
178
[Error: ENOENT: no such file or directory, open 'C:\Book samples\test.txt'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'C:\\Book samples\\test.txt'
If you skip the second argument and try to log the data, you’ll have a result like below:
<Buffer 48 69 20 74 68 65 72 65 21>
This is a buffer data, and encoding (charset) is needed to convert this into a readable form. The
second method used for reading files is readFileSynch, which is a synchronous, blocking
method. The arguments are the same as readFile except for the callback, which this method
doesn’t need one.
let data = fs.readFileSync('test.txt', 'utf-8')
console.log(data)
Since this method doesn’t have a callback, if there is an error reading the file specified, it will
throw an error, and you need to use a try-catch block to handle it.
let data
try {
data = fs.readFileSync('test.txt', 'utf-8')
} catch(e) {
console.log(e)
}
console.log(data)
Write
Using a write method will allow you to alter the data inside a file. There two methods
called writeFile and appendFile used for this purpose, which both have their synchronous
counterparts as well. Here is the signature for both methods:
fs.writeFile(file, data[, options], callback)
179
fs.appendFile(file, data[, options], callback)
The writeFile method will allow you to erase the data inside a file and write new data
inside it. The callback in these functions takes an argument showing the error if there are any.
fs.writeFile('test.txt', 'Hello world', err => {
if(err) throw err
console.log('Done!')
})
If the options argument is a string, it represents the encoding:
fs.writeFile('test.txt', 'Hello world', 'utf-8', err => {
if(err) throw err
console.log('Done!')
})
If you don’t want to wipe the data inside the file and append your data to it, you can use the
appendFile method, just like the writeFile method:
fs.appendFile('test.txt', 'Hello world', 'utf-8', err => {
if(err) throw err
console.log('Done!')
})
If the file doesn’t already exist, these methods will create such a file.
Rename
To rename a file, we can use the rename method, which its signature is as below:
fs.rename(oldPath, newPath, callback)
The oldPath argument is the current path to the file, and the newPath is where it should be.
Renaming a file is like moving a file.
fs.rename('a.txt', 'b.txt', err => {
if(err) throw err
console.log('Done')
})
If a directory is available, you can move the file into that directory:
fs.rename('b.txt', 'my-files/b.txt', err => {
if(err) throw err
console.log('Done')
180
})
Delete
Deleting a file is easy with fs. You only have to use the unlink method. The signature is
as below:
fs.unlink(path, callback)
fs.unlink('b.txt', err => {
if(err) throw err
console.log('Done')
})
Directory (folder)
Node.js file system allows you to work with directories as well as files.
Open
There are two methods for this particular task, which are opendir and opendirSync, and
their signatures are as below:
fs.opendir(path[, options], callback)
fs.opendirSync(path[, options])
fs.opendir('my-folder', (err, dir) => {
if(err) throw err
console.log(dir.constructor.name) // Dir
})
As you can test by yourself, the callback has an argument called dir, which is of type Dir. The
synchronous method returns such an object as well:
let dir = fs.opendirSync('my-folder')
console.log(dir.constructor.name) // Dir
Since this is a blocking method, we won’t be using it.
The options argument can be a string or an object representing the encoding
You can get the full path for your directory using the path property:
181
fs.opendir('my-folder', (err, dir) => {
if(err) throw err
console.log(dir.path) // my-folder
})
This might seem redundant, but it is useful when you don’t know which directory is open such as
when it is asked from the user to specify the folder.
Read
You can read a directory to return its content. You can use the readdir or its synchronous
counterpart:
fs.readdir(path[, options], callback)
The callback gets two arguments, one for the error as the convention, and the second one holding
the content of the directory in an array:
fs.readdir('my-folder', (err, content) => {
console.log(content) // [ 'another-folder', 'b.txt' ]
})
Create
To create a directory, you can use the mkdir method and its synchronous counterpart.
fs.mkdir(path[, options], callback)
fs.mkdir('new-folder', err => {
if(err) throw err
console.log('Done')
})
Rename
Renaming a folder is just as renaming a file.
fs.rename('folder-one', 'folder-two', err => {
if(err) throw err
console.log(err)
})
182
Delete
Deleting a directory is a simple task. You can use rmdir method and its synchronous
counterpart to delete a directory when it has no content in it.
fs.rmdir(path[, options], callback)
fs.rmdir('new-folder', err => {
if(err) throw err
console.log('Done')
})
If you try to delete a non-empty directory you will encounter an error:
fs.rmdir('my-folder', err => {
if(err) throw err
console.log('Done')
})
The code above will generate this error:
[Error: ENOTEMPTY: directory not empty, rmdir 'C:\Book samples\my-folder'] {
errno: -4051,
code: 'ENOTEMPTY',
syscall: 'rmdir',
path: 'C:\\Book samples\\my-folder'
If the directory is not empty, you should set an option called recursive true, so the file system
deletes everything inside the directory as well as the directory itself.
fs.rmdir('my-folder', {recursive: true}, err => {
if(err) throw err
console.log('Done')
})
183
Resources
Books
Algorithms by Robert Sedgewick and Kevin Wayne
Websites
https://developer.mozilla.org
https://www.w3schools.com/js/
https://www.tutorialsteacher.com/
https://eloquentjavascript.net/
https://www.techotopia.com/
https://nodejs.org/
184