Electron applications, being built with Node.js, have full access to the underlying operating system's file system. This is a powerful capability that allows your desktop apps to read, write, and manage files just like any other native application. Understanding how to interact with the file system is crucial for many common desktop application features, such as saving user preferences, opening and saving documents, managing project files, and more.
Node.js provides a built-in module called fs (File System) that exposes a comprehensive set of synchronous and asynchronous APIs for file operations. For Electron development, you'll primarily be using these fs module functions within your main process code, as it has direct access to the Node.js runtime.
The fs module offers two main styles of operation: synchronous and asynchronous. Synchronous operations block the Node.js event loop until the operation is complete, which can lead to unresponsive applications if not used carefully. Asynchronous operations, on the other hand, use callbacks or Promises, allowing other tasks to run while the file operation is in progress. For most user-facing operations in Electron, asynchronous methods are highly recommended to maintain a smooth user experience.
Let's explore some fundamental file system operations using the fs module.
To read the content of a file, you can use functions like fs.readFile() (asynchronous) or fs.readFileSync() (synchronous). The asynchronous version takes a file path, an optional options object (like encoding), and a callback function that receives an error object (if any) and the file data.
const fs = require('fs');
fs.readFile('my_document.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('File content:', data);
});For synchronous reading:
try {
const data = fs.readFileSync('my_document.txt', 'utf8');
console.log('File content:', data);
} catch (err) {
console.error('Error reading file:', err);
}Writing to files is done using fs.writeFile() (asynchronous) or fs.writeFileSync() (synchronous). You provide the file path, the data to write, and an optional options object (like encoding). The callback in the asynchronous version is called upon completion or error.
const contentToWrite = 'This is the content to be written to the file.';
fs.writeFile('output.txt', contentToWrite, 'utf8', (err) => {
if (err) {
console.error('Error writing file:', err);
return;
}
console.log('File written successfully!');
});Synchronous writing:
try {
fs.writeFileSync('output.txt', contentToWrite, 'utf8');
console.log('File written successfully!');
} catch (err) {
console.error('Error writing file:', err);
}You'll also frequently need to create, read, and delete directories. The fs module provides functions for this, such as fs.mkdir() and fs.rmdir() for directories, and fs.readdir() for listing directory contents.
Creating a directory:
fs.mkdir('new_directory', { recursive: true }, (err) => {
if (err) {
console.error('Error creating directory:', err);
return;
}
console.log('Directory created successfully!');
});Listing directory contents:
fs.readdir('.', (err, files) => {
if (err) {
console.error('Error reading directory:', err);
return;
}
console.log('Files in current directory:', files);
});For modern JavaScript development, especially with async/await, using the Promise-based API of the fs module is often preferred. Node.js offers this through require('fs').promises.
const fsPromises = require('fs').promises;
async function readFileContent(filePath) {
try {
const data = await fsPromises.readFile(filePath, 'utf8');
console.log('File content:', data);
} catch (err) {
console.error('Error reading file:', err);
}
}
readFileContent('my_document.txt');This Promise-based API makes asynchronous code much cleaner and easier to manage.
When working with file paths, it's essential to use the built-in path module. This module provides utilities for handling file and directory paths in a cross-platform compatible way, avoiding issues with different operating system conventions (like / vs. \ for separators).
const path = require('path');
const filePath = path.join(__dirname, 'assets', 'images', 'logo.png');
console.log('Constructed path:', filePath);Key path module functions include path.join(), path.resolve(), path.dirname(), and path.basename().
graph LR
A[Main Process] --> B{fs module};
B --> C[Read File];
B --> D[Write File];
B --> E[Create Directory];
B --> F[List Directory Contents];
A --> G{path module};
G --> H[Cross-platform Paths];
In summary, Node.js's fs and path modules are your primary tools for interacting with the file system in Electron. Always favor asynchronous operations for better performance and responsiveness in your desktop applications.