📜 ⬆️ ⬇️

Node.js Part 9 Guide: Working with the File System

Today, in the ninth part of the translation guide for Node.js, we will talk about working with files. In particular, the discussion deals with the modules fs and path - about file descriptors, about paths to files, about getting information about files, about reading and writing files, about working with directories.




Working with file descriptors in Node.js


Before you can interact with the files that are in the file system of your server, you need to get a file descriptor.
')
The handle can be obtained by using the asynchronous open() method from the fs module to open a file:

 const fs = require('fs') fs.open('/Users/flavio/test.txt', 'r', (err, fd) => { //fd -    }) 

Notice the second parameter, r , used when calling the fs.open() method. This is the flag that tells the system that the file is being opened for reading. Here are some more flags that are often used when working with this and some other methods:


Files can be opened and using the synchronous method fs.openSync() , which, instead of providing a file descriptor in a callback, returns it:

 const fs = require('fs') try { const fd = fs.openSync('/Users/flavio/test.txt', 'r') } catch (err) { console.error(err) } 

After receiving the handle by any of the methods described above, you can perform the necessary operations with it.

File information


Each file is associated with a set of data about it, you can explore this data using Node.js. In particular, this can be done using the stat() method from the fs module.

Call this method, passing it the path to the file, and, after Node.js receives the necessary information about the file, it will call the callback passed to the stat() method. Here's what it looks like:

 const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) {   console.error(err)   return } //      `stats` }) 

Node.js has the ability to synchronously get information about files. With this approach, the main stream is blocked until the properties of the file are obtained:

 const fs = require('fs') try { const stats = fs.statSync ('/Users/flavio/test.txt') } catch (err) { console.error(err) } 

File information will be in the stats constant. What is this information? In fact, the corresponding object provides us with a large number of useful properties and methods:


There are other methods, but these are the most commonly used. Here's how to use them:

 const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) {   console.error(err)   return } stats.isFile() //true stats.isDirectory() //false stats.isSymbolicLink() //false stats.size //1024000 //= 1MB }) 

Paths to files in Node.js and the path module


The file path is the address of the place in the file system where it is located.

On Linux and macOS, the path might look like this:

 /users/flavio/file.txt 

In Windows, the paths look a little different:

 C:\users\flavio\file.txt 

Differences in path recording formats when using different operating systems should be noted, given the operating system used to deploy the Node.js server.

Node.js has a standard path module, designed to work with file paths. Before using this module in the program, it must be connected:

 const path = require('path') 

â–ŤReceiving file path information


If you have a file path, then, using the capabilities of the path module, you can, in a convenient form for perception and further processing, to learn the details about this path. It looks like this:

 const notes = '/users/flavio/notes.txt' path.dirname(notes) // /users/flavio path.basename(notes) // notes.txt path.extname(notes) // .txt 

Here, in the notes line, the path to the file is stored. The following methods of the path module are used to parse the path :


You can find out the name of a file without an extension by calling the .basename() method and passing to it the second argument representing the extension:

 path.basename(notes, path.extname(notes)) //notes 

â–ŤWorking with file paths


Several parts of the path can be combined using the path.join() method:

 const name = 'flavio' path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 

You can find the absolute path to the file based on the relative path to it using the path.resolve() method:

 path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'       

In this case, Node.js simply adds /flavio.txt to the path leading to the current working directory. If, when calling this method, we pass another parameter representing the path to the folder, the method uses it as the basis for determining the absolute path:

 path.resolve('tmp', 'flavio.txt') // '/Users/flavio/tmp/flavio.txt'       

If the path passed as the first parameter begins with a slash, it means that it represents an absolute path.

 path.resolve('/etc', 'flavio.txt') // '/etc/flavio.txt' 

Another useful method is path.normalize() . It allows you to find the real file path using a path that contains relative path specifiers like a dot ( . ), Two dots ( .. ), or two slashes:

 path.normalize('/users/flavio/..//test.txt') // /users/test.txt 

The resolve() and normalize() methods do not verify the existence of a directory. They simply find the path based on the data passed to them.

Reading files in Node.js


The easiest way to read files in Node.js is to use the fs.readFile() method with passing it the path to the file and a callback that will be called with passing it the file data (or the error object):

 fs.readFile('/Users/flavio/test.txt', (err, data) => { if (err) {   console.error(err)   return } console.log(data) }) 

If necessary, you can use the synchronous version of this method - fs.readFileSync() :

 const fs = require('fs') try { const data = fs.readFileSync('/Users/flavio/test.txt') console.log(data) } catch (err) { console.error(err) } 

By default, the utf8 encoding is used when reading files, but the encoding can also be set independently by passing the corresponding parameter to the method.

The fs.readFile() and fs.readFileSync() methods read the entire contents of the file into memory. This means that working with large files using these methods will seriously affect the memory consumption of your application and will affect its performance. If you need to work with such files, it is best to use streams.

Writing Files to Node.js


In Node.js, it is easiest to write files using the fs.writeFile() method:

 const fs = require('fs') const content = 'Some content!' fs.writeFile('/Users/flavio/test.txt', content, (err) => { if (err) {   console.error(err)   return } //   }) 

There is a synchronous version of the same method - fs.writeFileSync() :

 const fs = require('fs') const content = 'Some content!' try { const data = fs.writeFileSync('/Users/flavio/test.txt', content) //   } catch (err) { console.error(err) } 

These methods, by default, replace the contents of existing files. You can change their standard behavior using the appropriate flag:

 fs.writeFile('/Users/flavio/test.txt', content, { flag: 'a+' }, (err) => {}) 

Here flags which we already listed in the section devoted to descriptors can be used. Details about the flags can be found here .

Attaching data to a file


The fs.appendFile() method (and its synchronous version - fs.appendFileSync() ) is conveniently used to fs.appendFileSync() data to the end of the file:

 const content = 'Some content!' fs.appendFile('file.log', content, (err) => { if (err) {   console.error(err)   return } //! }) 

About using threads


Above, we described methods that, writing to a file, write to it the entire amount of the data transferred to them, after which, if their synchronous versions are used, they return control to the program, and if asynchronous versions are used, they call callbacks. If you are not satisfied with this state of affairs, it would be better to use threads.

Working with directories in Node.js


The fs module provides the developer with many convenient methods that can be used to work with directories.

â–Ť Check folder existence


In order to check whether a directory exists and whether Node.js can access it, given its permissions, you can use the fs.access() method.

â–ŤCreate a new folder


In order to create new folders, you can use the fs.mkdir() and fs.mkdirSync() methods:

 const fs = require('fs') const folderName = '/Users/flavio/test' try { if (!fs.existsSync(dir)){   fs.mkdirSync(dir) } } catch (err) { console.error(err) } 

â–ŤRead folder contents


In order to read the contents of the folder, you can use the fs.readdir() and fs.readdirSync() methods. In this example, the contents of the folder are read — that is, information on which files and subdirectories are in it, and the return of their relative paths:

 const fs = require('fs') const path = require('path') const folderPath = '/Users/flavio' fs.readdirSync(folderPath) 

This is how you can get the full path to the file:

 fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName) } 

Results can be filtered to get only files and exclude from directory output:

 const isFile = fileName => { return fs.lstatSync(fileName).isFile() } fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName)).filter(isFile) } 

â–Ť Rename folder


To rename a folder, you can use the fs.rename() and fs.renameSync() methods. The first parameter is the current path to the folder, the second is the new one:

 const fs = require('fs') fs.rename('/Users/flavio', '/Users/roger', (err) => { if (err) {   console.error(err)   return } // }) 

You can also rename a folder using the synchronous fs.renameSync() method:

 const fs = require('fs') try { fs.renameSync('/Users/flavio', '/Users/roger') } catch (err) { console.error(err) } 

â–ŤDelete folder


In order to remove a folder, you can use the fs.rmdir() or fs.rmdirSync() methods. It should be noted that deleting a folder in which there is something, the task is somewhat more complicated than deleting an empty folder. If you need to delete such folders, use the fs-extra package, which is very popular and well supported. It is a replacement for the fs module, expanding its capabilities.

The remove() method from the fs-extra package can remove folders that already have something in it.

You can install this module as follows:

 npm install fs-extra 

Here is an example of its use:

 const fs = require('fs-extra') const folder = '/Users/flavio' fs.remove(folder, err => { console.error(err) }) 

His methods can be used in the form of promises:

 fs.remove(folder).then(() => { // }).catch(err => { console.error(err) }) 

It is also possible to use the async / await construction:

 async function removeFolder(folder) { try {   await fs.remove(folder)   // } catch (err) {   console.error(err) } } const folder = '/Users/flavio' removeFolder(folder) 

Fs module


Above, we have come across some of the fs module methods used when working with the file system. In fact, it contains a lot more useful. Recall that it does not need to be installed, in order to use it in the program, it is enough to connect it:

 const fs = require('fs') 

After that, you will have access to his methods, among which we note the following, some of which you already know:


An interesting feature of the fs module is the fact that all its methods, by default, are asynchronous, but there are also their synchronous versions, whose names are obtained by adding the word Sync to the names of asynchronous methods.

For example:


Using synchronous methods seriously affects how the program works.

Node.js 10 has experimental support for these promis based APIs.

Investigate the fs.rename() method. Here is an asynchronous version of this method using callbacks:

 const fs = require('fs') fs.rename('before.json', 'after.json', (err) => { if (err) {   return console.error(err) } // }) 

When using its synchronous version, try/catch used for error handling:

 const fs = require('fs') try { fs.renameSync('before.json', 'after.json') // } catch (err) { console.error(err) } 

The main difference between these options for using this method is that in the second case script execution will be blocked until the file operation is completed.

Path module


The path module, of which some of the features we have already mentioned, contains many useful tools that allow you to interact with the file system. As already mentioned, it is not necessary to install it, since it is part of Node.js. In order to use it, it is enough to connect it:

 const path = require('path') 

The path.sep property of this module provides the symbol used to separate the segments of the path ( \ on Windows and / on Linux and macOS), and the path.delimiter property gives the symbol used to separate several paths from each other ( ; on Windows and : on Linux and macOS).

Consider and illustrate with examples some methods of the path module.

Athpath.basename ()


Returns the last fragment of the path. By passing the second parameter to this method, you can remove the file extension.

 require('path').basename('/test/something') //something require('path').basename('/test/something.txt') //something.txt require('path').basename('/test/something.txt', '.txt') //something 

Athpath.dirname ()


Returns the part of the path that represents the directory name:

 require('path').dirname('/test/something') // /test require('path').dirname('/test/something/file.txt') // /test/something 

Athpath.extname ()


Returns that part of the path that represents the file extension:

 require('path').extname('/test/something') // '' require('path').extname('/test/something/file.txt') // '.txt' 

Athpath.isAbsolute ()


Returns true value if the path is absolute:

 require('path').isAbsolute('/test/something') // true require('path').isAbsolute('./test/something') // false 

Athpath.join ()


Connects several parts of the path:

 const name = 'flavio' require('path').join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 

â–Ťpath.normalize ()


Trying to figure out the real path based on the path that contains the characters used in constructing relative paths like . , .. and // :

 require('path').normalize('/users/flavio/..//test.txt') ///users/test.txt 

Athpath.parse ()


Converts a path to an object whose properties represent separate parts of the path:


Here is an example of using this method:

 require('path').parse('/users/test.txt') 

As a result of his work, this object is obtained:

 { root: '/', dir: '/users', base: 'test.txt', ext: '.txt', name: 'test' } 

Athpath.relative ()


Accepts, as arguments, 2 ways. Returns the relative path from the first path to the second, based on the current working directory:

 require('path').relative('/Users/flavio', '/Users/flavio/test.txt') //'test.txt' require('path').relative('/Users/flavio', '/Users/flavio/something/test.txt') //'something/test.txt' 

Athpath.resolve ()


Finds an absolute path based on the relative path passed to it:

 path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'      . 

Results


Today we looked at the Node.js fs and path modules that are used to work with the file system. In the next part of this series, where it ends, we will discuss the modules os , events , http , talk about working with threads and database management systems in Node.js.

Dear readers! What npm packages do you use when working with the file system in Node.js?

Source: https://habr.com/ru/post/424969/


All Articles