0% found this document useful (0 votes)
7 views14 pages

NodeJS Part2 CoreModules FileSystem

This document is Part 2 of a 10-part series on Node.js, focusing on core modules and file system operations. It covers the essential built-in modules, particularly the File System (fs) module, detailing how to perform various file operations such as reading, writing, deleting, and checking file properties. Additionally, it introduces the path module for handling file paths and provides practical examples for file logging and copying utilities.

Uploaded by

alvinregi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views14 pages

NodeJS Part2 CoreModules FileSystem

This document is Part 2 of a 10-part series on Node.js, focusing on core modules and file system operations. It covers the essential built-in modules, particularly the File System (fs) module, detailing how to perform various file operations such as reading, writing, deleting, and checking file properties. Additionally, it introduces the path module for handling file paths and provides practical examples for file logging and copying utilities.

Uploaded by

alvinregi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Node.

js Complete Guide

Part 2: Core Modules and File System Operations

Part 2 of 10-Part Series

In Part 1, we explored the fundamentals of [Link], its architecture, and basic concepts. Now,
we'll dive deep into [Link] core modules, which are built-in modules that provide essential
functionality without requiring external packages. We'll pay special attention to the File
System (fs) module, one of the most commonly used core modules in [Link] development.

1. Understanding [Link] Core Modules

Core modules are built-in modules that come packaged with [Link]. They provide essential
functionality for building applications and can be used without installation. These modules are
loaded using the require() function without any path prefix.

1.1 How to Use Core Modules

To use a core module, you simply require it in your code. [Link] will automatically locate and
load the module from its internal library. Here's the basic syntax:
// Requiring a core module const fs = require('fs'); const path =
require('path'); const http = require('http'); // Using ES6 module syntax
(with .mjs files or "type": "module" in [Link]) import fs from 'fs';
import path from 'path'; import http from 'http';

1.2 Overview of Essential Core Modules

Module Purpose

fs File system operations (read, write, delete files)

path Handle and transform file paths

http/https Create HTTP/HTTPS servers and make requests

events Event emitter for handling events


stream Handle streaming data

util Utility functions for debugging and formatting

os Operating system-related information

crypto Cryptographic functionality

buffer Handle binary data

child_process Spawn child processes

url URL parsing and formatting

querystring Parse and format URL query strings


2. The File System (fs) Module

The fs module is one of the most important core modules in [Link]. It provides an API for
interacting with the file system in a manner closely modeled around standard POSIX
functions. All file system operations have both synchronous and asynchronous forms.

2.1 Synchronous vs Asynchronous Operations

The fs module offers two forms of operations:

Asynchronous (Non-blocking): These methods take a callback function as the last


argument, which is called when the operation completes. The program continues execution
without waiting.

Synchronous (Blocking): These methods have 'Sync' appended to their names and block
the execution until the operation completes. They should be avoided in production servers as
they can impact performance.

// Asynchronous (Recommended for production) const fs = require('fs');


[Link]('[Link]', 'utf8', (err, data) => { if (err) {
[Link]('Error reading file:', err); return; } [Link]('File
contents:', data); }); [Link]('This executes before file reading
completes'); // Synchronous (Use cautiously) try { const data =
[Link]('[Link]', 'utf8'); [Link]('File contents:', data);
} catch (err) { [Link]('Error reading file:', err); }
[Link]('This executes after file reading completes');

2.2 Reading Files

2.2.1 Reading Entire File


The [Link]() method reads the entire contents of a file asynchronously. It's suitable for
small to medium-sized files.
const fs = require('fs'); // Reading a text file [Link]('[Link]',
'utf8', (err, data) => { if (err) { [Link]('Error:', err); return; }
[Link]('Content:', data); }); // Reading a binary file (image, PDF,
etc.) [Link]('[Link]', (err, data) => { if (err) throw err;
[Link]('Binary data buffer:', data); // data is a Buffer object }); //
Using Promises ([Link]) const fsPromises = require('fs').promises; async
function readFileAsync() { try { const data = await
[Link]('[Link]', 'utf8'); [Link]('Content:', data); }
catch (err) { [Link]('Error:', err); } } readFileAsync();

2.2.2 Reading Files in Chunks (Streams)


For large files, it's more efficient to read the file in chunks using streams. This prevents
loading the entire file into memory.
const fs = require('fs'); // Create a readable stream const readStream =
[Link]('[Link]', { encoding: 'utf8', highWaterMark: 16 *
1024 // 16KB chunks }); // Handle stream events [Link]('data', (chunk)
=> { [Link]('Received chunk:', [Link], 'bytes'); });
[Link]('end', () => { [Link]('Finished reading file'); });
[Link]('error', (err) => { [Link]('Error:', err); });
2.3 Writing Files

2.3.1 Writing to Files


The [Link]() method writes data to a file, replacing the file if it already exists. The
[Link]() method appends data to a file.
const fs = require('fs'); // Writing to a file (overwrites existing content)
const content = 'This is the new content of the file.';
[Link]('[Link]', content, 'utf8', (err) => { if (err) {
[Link]('Error writing file:', err); return; } [Link]('File
written successfully!'); }); // Appending to a file [Link]('[Link]',
'New log entry\n', (err) => { if (err) { [Link]('Error appending to
file:', err); return; } [Link]('Content appended successfully!'); }); //
Writing JSON data const jsonData = { name: 'John Doe', age: 30, city: 'New
York' }; [Link]('[Link]', [Link](jsonData, null, 2), (err)
=> { if (err) throw err; [Link]('JSON data saved!'); }); // Using
Promises const fsPromises = require('fs').promises; async function
writeFileAsync() { try { await [Link]('[Link]',
'Async content'); [Link]('File written asynchronously!'); } catch (err)
{ [Link]('Error:', err); } } writeFileAsync();

2.3.2 Writing Large Files (Streams)


For writing large amounts of data, use writable streams to avoid memory issues.
const fs = require('fs'); // Create a writable stream const writeStream =
[Link]('[Link]'); // Write data in chunks
[Link]('First line\n'); [Link]('Second line\n');
[Link]('Third line\n'); // Close the stream [Link]('Final
line\n'); // Handle events [Link]('finish', () => { [Link]('All
data written to file'); }); [Link]('error', (err) => {
[Link]('Error writing to file:', err); });

2.4 File Operations

2.4.1 Deleting Files


const fs = require('fs'); // Delete a file [Link]('[Link]',
(err) => { if (err) { [Link]('Error deleting file:', err); return; }
[Link]('File deleted successfully'); }); // Using Promises const
fsPromises = require('fs').promises; async function deleteFile() { try {
await [Link]('[Link]'); [Link]('File deleted
successfully'); } catch (err) { [Link]('Error:', err); } }

2.4.2 Renaming and Moving Files


const fs = require('fs'); // Rename a file [Link]('[Link]',
'[Link]', (err) => { if (err) { [Link]('Error renaming file:',
err); return; } [Link]('File renamed successfully'); }); // Move a file
to different directory [Link]('[Link]', './newfolder/[Link]', (err) =>
{ if (err) { [Link]('Error moving file:', err); return; }
[Link]('File moved successfully'); });

2.4.3 Copying Files


const fs = require('fs'); // Copy a file [Link]('[Link]',
'[Link]', (err) => { if (err) { [Link]('Error copying file:',
err); return; } [Link]('File copied successfully'); }); // Copy with
flag to prevent overwriting [Link]('[Link]', '[Link]',
[Link].COPYFILE_EXCL, (err) => { if (err) { [Link]('Destination
file already exists'); return; } [Link]('File copied successfully'); });
2.5 Checking File Existence and Properties

2.5.1 Checking if File Exists


const fs = require('fs'); // Using [Link]() (Recommended)
[Link]('[Link]', [Link].F_OK, (err) => { if (err) {
[Link]('File does not exist'); return; } [Link]('File exists'); });
// Check if file is readable [Link]('[Link]', [Link].R_OK, (err)
=> { if (err) { [Link]('File is not readable'); return; }
[Link]('File is readable'); }); // Check if file is writable
[Link]('[Link]', [Link].W_OK, (err) => { if (err) {
[Link]('File is not writable'); return; } [Link]('File is
writable'); }); // Using Promises const fsPromises = require('fs').promises;
async function checkFile() { try { await [Link]('[Link]');
[Link]('File exists'); } catch { [Link]('File does not exist'); } }

2.5.2 Getting File Information


The [Link]() method provides detailed information about a file or directory.
const fs = require('fs'); [Link]('[Link]', (err, stats) => { if (err) {
[Link]('Error:', err); return; } [Link]('File Info:');
[Link]('Size:', [Link], 'bytes'); [Link]('Is file:',
[Link]()); [Link]('Is directory:', [Link]());
[Link]('Created:', [Link]); [Link]('Modified:',
[Link]); [Link]('Accessed:', [Link]); // File permissions
[Link]('Mode:', [Link]); }); // Using Promises const fsPromises =
require('fs').promises; async function getFileInfo() { try { const stats =
await [Link]('[Link]'); [Link]('File size:', [Link]); }
catch (err) { [Link]('Error:', err); } }

2.6 Directory Operations

2.6.1 Creating Directories


const fs = require('fs'); // Create a single directory [Link]('newdir',
(err) => { if (err) { [Link]('Error creating directory:', err);
return; } [Link]('Directory created'); }); // Create nested directories
[Link]('parent/child/grandchild', { recursive: true }, (err) => { if (err)
{ [Link]('Error:', err); return; } [Link]('Nested directories
created'); }); // Using Promises const fsPromises = require('fs').promises;
async function createDirectory() { try { await [Link]('newdir', {
recursive: true }); [Link]('Directory created successfully'); } catch
(err) { [Link]('Error:', err); } }

2.6.2 Reading Directory Contents


const fs = require('fs'); // Read directory contents [Link]('./mydir',
(err, files) => { if (err) { [Link]('Error reading directory:', err);
return; } [Link]('Files in directory:', files); // files is an array of
filenames }); // Read with file types [Link]('./mydir', { withFileTypes:
true }, (err, entries) => { if (err) { [Link]('Error:', err); return;
} [Link](entry => { [Link]([Link], '-', [Link]()
? 'Directory' : 'File'); }); }); // Using Promises const fsPromises =
require('fs').promises; async function listFiles() { try { const files =
await [Link]('./mydir'); [Link](file => {
[Link](file); }); } catch (err) { [Link]('Error:', err); } }

2.6.3 Removing Directories


const fs = require('fs'); // Remove empty directory [Link]('emptydir',
(err) => { if (err) { [Link]('Error removing directory:', err);
return; } [Link]('Directory removed'); }); // Remove directory and its
contents (recursive) [Link]('mydir', { recursive: true, force: true }, (err)
=> { if (err) { [Link]('Error:', err); return; }
[Link]('Directory and contents removed'); }); // Using Promises const
fsPromises = require('fs').promises; async function removeDirectory() { try {
await [Link]('mydir', { recursive: true }); [Link]('Directory
removed successfully'); } catch (err) { [Link]('Error:', err); } }
3. The Path Module

The path module provides utilities for working with file and directory paths. It handles
path-related operations in a cross-platform manner, automatically handling differences
between Windows and Unix-based systems.

3.1 Common Path Operations

const path = require('path'); // Join path segments const fullPath =


[Link]('/users', 'john', 'documents', '[Link]'); [Link](fullPath);
// /users/john/documents/[Link] // Resolve absolute path const absolutePath
= [Link]('docs', '[Link]'); [Link](absolutePath); //
/current/working/directory/docs/[Link] // Get directory name const dirName
= [Link]('/users/john/documents/[Link]'); [Link](dirName); //
/users/john/documents // Get file name const fileName =
[Link]('/users/john/documents/[Link]'); [Link](fileName); //
[Link] // Get file extension const ext = [Link]('[Link]');
[Link](ext); // .txt // Parse path into components const pathInfo =
[Link]('/users/john/documents/[Link]'); [Link](pathInfo); // { //
root: '/', // dir: '/users/john/documents', // base: '[Link]', // ext:
'.txt', // name: 'file' // } // Format path from components const formatted =
[Link]({ dir: '/users/john/documents', base: '[Link]' });
[Link](formatted); // /users/john/documents/[Link] // Get relative
path const relative = [Link]('/users/john',
'/users/john/documents/[Link]'); [Link](relative); //
documents/[Link] // Normalize path (resolve . and ..) const normalized =
[Link]('/users/john/../jane/./documents'); [Link](normalized);
// /users/jane/documents

4. Practical Examples

4.1 File Logger


Creating a simple file-based logger that appends log entries with timestamps.
const fs = require('fs'); const path = require('path'); class FileLogger {
constructor(logFile) { [Link] = logFile; // Ensure log directory exists
const logDir = [Link](logFile); if (![Link](logDir)) {
[Link](logDir, { recursive: true }); } } log(level, message) { const
timestamp = new Date().toISOString(); const logEntry = `[${timestamp}]
[${level}] ${message}\n`; [Link]([Link], logEntry, (err) => { if
(err) { [Link]('Failed to write log:', err); } }); } info(message) {
[Link]('INFO', message); } error(message) { [Link]('ERROR', message); }
warn(message) { [Link]('WARN', message); } } // Usage const logger = new
FileLogger('./logs/[Link]'); [Link]('Application started');
[Link]('An error occurred'); [Link]('This is a warning');

4.2 File Copy Utility


A utility function to copy files with error handling and progress reporting.
const fs = require('fs'); const path = require('path'); async function
copyFile(source, destination) { return new Promise((resolve, reject) => { //
Check if source exists if (![Link](source)) { return reject(new
Error('Source file does not exist')); } // Ensure destination directory
exists const destDir = [Link](destination); if
(![Link](destDir)) { [Link](destDir, { recursive: true }); } //
Create read and write streams const readStream = [Link](source);
const writeStream = [Link](destination); // Handle errors
[Link]('error', reject); [Link]('error', reject); // Handle
completion [Link]('finish', () => { resolve('File copied
successfully'); }); // Pipe data from read to write stream
[Link](writeStream); }); } // Usage copyFile('./source/[Link]',
'./backup/[Link]') .then(message => [Link](message)) .catch(err =>
[Link]('Copy failed:', err));
4.3 Directory Tree Scanner
Recursively scan a directory and list all files with their sizes.
const fs = require('fs').promises; const path = require('path'); async
function scanDirectory(dirPath, level = 0) { try { const entries = await
[Link](dirPath, { withFileTypes: true }); for (const entry of entries) {
const fullPath = [Link](dirPath, [Link]); const indent = '
'.repeat(level); if ([Link]()) { [Link](`${indent}■
${[Link]}/`); await scanDirectory(fullPath, level + 1); } else { const
stats = await [Link](fullPath); const size = ([Link] / 1024).toFixed(2);
[Link](`${indent}■ ${[Link]} (${size} KB)`); } } } catch (err) {
[Link](`Error scanning ${dirPath}:`, [Link]); } } // Usage
scanDirectory('./myproject').then(() => { [Link]('\nScan complete!');
});

4.4 JSON Configuration Manager


A simple configuration manager for reading and writing JSON configuration files.
const fs = require('fs').promises; const path = require('path'); class
ConfigManager { constructor(configPath) { [Link] = configPath;
[Link] = {}; } async load() { try { const data = await
[Link]([Link], 'utf8'); [Link] = [Link](data); return
[Link]; } catch (err) { if ([Link] === 'ENOENT') { // File doesn't
exist, create with defaults [Link] = {}; await [Link](); } else {
throw err; } } } async save() { const configDir =
[Link]([Link]); await [Link](configDir, { recursive: true
}); await [Link]( [Link], [Link]([Link], null, 2)
); } get(key, defaultValue = null) { return [Link][key] !== undefined ?
[Link][key] : defaultValue; } set(key, value) { [Link][key] =
value; } async update(key, value) { [Link](key, value); await [Link]();
} } // Usage async function main() { const config = new
ConfigManager('./config/[Link]'); await [Link]();
[Link]('appName', 'My App'); [Link]('version', '1.0.0');
[Link]('port', 3000); await [Link](); [Link]('App Name:',
[Link]('appName')); [Link]('Port:', [Link]('port')); }
main().catch([Link]);

5. Best Practices

1. Always Use Asynchronous Methods in Production: Synchronous methods block the


event loop and can severely impact performance. Use them only in scripts or during
application startup.

2. Always Handle Errors: File operations can fail for many reasons (permissions, disk space,
network issues). Always implement proper error handling.

3. Use Promises or Async/Await: Modern [Link] applications should prefer Promises or


async/await over callbacks to avoid callback hell and improve code readability.
4. Use Streams for Large Files: When dealing with large files, use streams instead of
reading/writing the entire file at once to conserve memory.

5. Use the Path Module: Always use the path module for path operations to ensure
cross-platform compatibility.

6. Validate File Paths: Always validate and sanitize file paths, especially when they come
from user input, to prevent directory traversal attacks.

7. Check File Existence Before Operations: Use [Link]() to check if a file exists and is
accessible before performing operations on it.

8. Close File Descriptors: When using low-level file operations with [Link](), always close
file descriptors with [Link]() to prevent resource leaks.

9. Use Appropriate File Encoding: Specify encoding ('utf8', 'ascii', etc.) when reading text
files. Binary files should be read without encoding.

10. Implement Proper Logging: Log file operations, especially in production, to help with
debugging and monitoring.
6. Common Pitfalls to Avoid

1. Not Handling File Descriptor Limits: Opening too many files simultaneously can hit OS
limits. Use connection pooling or limit concurrent operations.

2. Race Conditions: When multiple processes or async operations access the same file, race
conditions can occur. Use file locking mechanisms when necessary.

3. Memory Leaks with Streams: Not properly handling stream errors or not closing streams
can cause memory leaks.

4. Ignoring File Permissions: Always check and handle permission errors appropriately.

5. Not Using Absolute Paths: Relative paths can cause issues depending on where the
script is executed from. Use [Link]() or __dirname to create absolute paths.

6. Blocking the Event Loop: Using synchronous operations in request handlers or callbacks
can severely degrade performance.

7. Not Checking Disk Space: Large write operations can fail if disk space is insufficient.
Consider checking available space for critical operations.

7. Performance Optimization Tips

1. Use Streams for Large Files: Streams process data in chunks, reducing memory usage
significantly.

2. Implement Caching: Cache frequently accessed file data in memory to reduce I/O
operations.

3. Batch Operations: When performing multiple file operations, batch them together to
reduce overhead.

4. Use Buffer Pooling: Reuse buffers when possible to reduce garbage collection pressure.

5. Optimize File Access Patterns: Sequential access is faster than random access.
Organize data access patterns accordingly.

6. Use Compression: For large files, consider compression to reduce I/O time, especially
over networks.

7. Monitor and Profile: Use [Link] profiling tools to identify bottlenecks in file operations.

8. Consider SSD vs HDD: Be aware of storage medium characteristics; SSDs handle


random access better than HDDs.
8. Summary

In this part, we've covered the essential core modules of [Link] with a deep focus on the File
System (fs) module. We've learned about:

• Understanding and using [Link] core modules


• Reading and writing files using various methods
• Working with streams for efficient large file handling
• Performing file operations (delete, rename, copy)
• Checking file existence and properties
• Managing directories (create, read, remove)
• Using the path module for cross-platform path operations
• Implementing practical file-based utilities
• Following best practices and avoiding common pitfalls
• Optimizing file system operations for performance

The fs module is fundamental to [Link] development, and mastering it opens doors to


building robust server-side applications, build tools, file processors, and much more.

9. What's Next in Part 3?

In Part 3, we'll explore Asynchronous Programming in [Link], covering:

• Understanding the Event Loop in depth


• Working with Callbacks and handling callback hell
• Using Promises for cleaner asynchronous code
• Mastering Async/Await syntax
• Error handling in asynchronous operations
• Understanding Promises chaining and composition
• Working with multiple concurrent operations
• Best practices for asynchronous programming

Asynchronous programming is at the heart of [Link]'s power and efficiency. Part 3 will give
you the tools to write clean, efficient, and maintainable asynchronous code.

This concludes Part 2 of the [Link] Complete Guide. Practice the examples provided and
experiment with different file operations to solidify your understanding before moving to Part 3.

You might also like