Node.js Fundamentals: Buffers and File System Operations

Basic Concepts

Node.js is a JavaScript runtime environment built on Chrome's V8 engine. It utilizes an event-driven, non-blocking I/O model that enables JavaScript to run on the server side.

Official website: https://nodejs.org

Code example:

console.log("hello Node.js");

// 1. Navigate to the directory containing the js file
// 2. Execute node hello.js
// 3. Output: hello Node.js

Sample code repository: https://github.com/yourusername/nodejs-basics

Buffer

Concept

Buffer is an array-like object used to represent fixed-length byte sequences. Essentially, it's a memory space specifically designed for handling binary data.

Characteristics

  • Buffer size is fixed and cannot be adjusted
  • Buffer offers better performance as it directly operates on computer memory
  • Each element occupies 1 byte

Usage

Buffer Creation

There are several ways to create a Buffer in Node.js:

Buffer.alloc
// Creates a 10-byte Buffer, equivalent to allocating 10 bytes of memory space with each byte value set to 0
// Result: <Buffer 00 00 00 00 00 00 00 00 00 00>
const buffer1 = Buffer.alloc(10);
Buffer.allocUnsafe
// Creates a 10-byte Buffer that may contain old data, which could affect execution results, hence the name 'unsafe'
const buffer2 = Buffer.allocUnsafe(10);
Buffer.from
// Create Buffer from string
const buffer3 = Buffer.from('hello');
// Create Buffer from array
const buffer4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
Buffer and String Conversion

Use the toString method to convert Buffer to string:

const buffer = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
// Default encoding is UTF-8
console.log(buffer.toString());

Note: toString uses UTF-8 encoding by default.

Buffer Operations

Buffer can be processed using array notation:

const buffer = Buffer.from('hello');
// Binary: 1101000
console.log(buffer[0].toString(2));

// Modify buffer
buffer[0] = 95;
console.log(buffer.toString());

// Overflow: If the modified value exceeds 255, the excess 8-bit data will be discarded
const buffer = Buffer.from('hello');
// High-order bits will be discarded because the maximum value for 8 bits is 255
buffer[0] = 361;
console.log(buffer);

// Chinese characters: A UTF-8 character typically occupies 3 bytes
const buffer = Buffer.from('你好');
console.log(buffer);

Note: If the modified value exceeds 255, excess bits will be discarded. A UTF-8 character typically occupies 3 bytes.

File System Module

The fs (file system) module is a built-in Node.js module that allows operations on the computer's disk.

File Writing

File writing involves saving data to a file. The following APIs are available:

Method Description
writeFile Asynchronous writing
writeFileSync Synchronous writing
appendFile/appendFileSync Append writing
createWriteStream Stream writing
Asynchronous Writing

Syntax: fs.writeFile(file, data, [options], callback)

Parameters:

  • file: filename
  • data: data to be written
  • options: option settings (optional)
  • callback: write callback

Return value: undefined

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Write to file
// writeFile asynchronously writes with four parameters: 1. file path 2. content 3. configuration 4. callback function
// File write successful
fs.writeFile('./motto.txt', 'Conquer the wolves, meditate at Gu Yan, drink horses at the sea', error => {
    // Error is null when writing is successful
    if (error) {
        console.log('File write failed');
        return;
    }
    console.log('File write successful');
});
Synchronous Writing

Syntax: fs.writeFileSync(file, data, [options])

Parameters:

  • file: filename
  • data: data to be written
  • options: option settings (optional)

Return value: undefined

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Write to file
// Synchronous write without callback function
fs.writeFileSync('./motto.txt', 'Conquer the wolves, meditate at Gu Yan, drink horses at the sea');

In Node.js, disk operations are performed by other threads. There are two processing modes:

  • Synchronous processing: The JavaScript main thread waits for the execution results of other threads before continuing with main thread code, which is less efficient
  • Asynchronous processing: The JavaScript main thread doesn't wait for the execution results of other threads and directly continues with subsequent main thread code, which is more efficient
Append Writing

The appendFile function appends content to the end of a file. Its syntax is identical to writeFile.

Syntax:

  • fs.appendFile(file, data, [options], callback)
  • fs.appendFileSync(file, data, [options])

Return value: Both are undefined

Code example:

// 1. Import fs module
const fs = require('fs');

const content = '\r\nBut if the Flying General of Dragon City is still here, the Hu horses shall not cross the Yin Mountains.';

// fs.appendFile('./motto.txt', content, error => {
//     // Error is null when writing is successful
//     if (error) {
//         console.log('File append write failed');
//         return;
//     }
//     console.log('File append write successful');
// });

// Synchronous file append write
// fs.appendFileSync('./motto.txt', content);

// Use writeFile for append writing
fs.writeFile('./motto.txt', content, {flag: 'a'}, error => {
    if (error) {
        console.log('File append write failed');
        return;
    }
    console.log('File append write successful');
});

console.log('hello world');
Stream Writing

Syntax: fs.createWriteStream(path, [options])

Parameters:

  • path: file path
  • options: option configuration (optional)

Return value: Object

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Create write stream object
const writeStream = fs.createWriteStream('./reading.txt');

// 3. Write content
writeStream.write('A half-acre pond like a mirror opens\r\n');
writeStream.write('Sky and clouds shadows徘徊 together\r\n');
writeStream.write('Ask how the channel gets so clear\r\n');
writeStream.write('Because there is a living source of water\r\n');

// 4. Close the channel (not necessary)
// writeStream.close();

Opening a file consumes resources. Stream writing reduces the number of times files are opened and closed. Stream writing is suitable for large file writing or frequent writing scenarios, while writeFile is suitable for scenarios with low writing frequency.

File Reading

File reading involves retrieving data from files through programs. The following APIs are available:

Method Description
readFile Asynchronous reading
readFileSync Synchronous reading
createReadStream Stream reading
Asynchronous Reading

Syntax: fs.readFile(path, [options], callback)

Parameters:

  • path: file path
  • options: option configuration
  • callback: callback function

Return value: undefined

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Asynchronous read
fs.readFile('./motto.txt', (error, data) => {
    if (error) {
        console.log('File read error');
        return;
    }
    console.log(data.toString());
});
Synchronous Reading

Syntax: fs.readFileSync(path, [options])

Parameters:

  • path: file path
  • options: option configuration

Return value: string | Buffer

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Synchronous read
let data = fs.readFileSync('./motto.txt');
console.log(data.toString());
Stream Reading

Syntax: fs.createReadStream(path, [options])

Parameters:

  • path: file path
  • options: option configuration (optional)

Return value: Object

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Create read stream object
const rs = fs.createReadStream('./reading.txt');

// 3. Bind data event
rs.on('data', chunk => {
    // chunk: block, large piece
    console.log(chunk);
    console.log(chunk.length);
    console.log(chunk.toString());
});

// 4. End event (optional)
rs.on('end', () => {
    console.log('File reading completed');
});

File Moving and Renaming

In Node.js, you can use rename or renameSync to move or rename files or folders.

Syntax:

  • fs.rename(oldPath, newPath, callback)
  • fs.renameSync(oldPath, newPath)

Parameters:

  • oldPath: current file path
  • newPath: new file path
  • callback: callback after operation

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. File rename
// fs.rename('./motto-2.txt', './famous-general.txt', error => {
//     if (error) {
//         console.log('File rename failed');
//            return ;
//     }
//     console.log('File rename successful');
// });

// 3. File move
// Error will be thrown if the folder doesn't exist: Error: ENOENT: no such file or directory
fs.rename('./famous-general.txt', './files/famous-general.txt', error => {
    if (error) {
        console.log(error, 'Error moving file');
        return ;
    }
    console.log('Operation successful');
});

File Deletion

In Node.js, you can use unlink or unlinkSync or rm or rmSync to delete files.

Syntax:

  • fs.unlink(path, callback)
  • fs.unlinkSync(path)

Parameters:

  • path: file path
  • callback: callback after operation

Code example:

// 1. Import fs module
const fs = require('fs');

// 2. Call unlink method
// unlinkSync: synchronous deletion
// fs.unlink('./motto-3.txt', error => {
//     if (error) {
//         console.log('Delete file error', error)
//         return;
//     }
//     console.log('Delete file successful')
// });

// 3. Call rm method
// rmSync: synchronous deletion
fs.rm('./files/famous-general.txt', error => {
    if (error) {
        console.log('File deletion failed', error)
        return;
    }
    console.log('File deletion successful')
});

Folder Operations

In Node.js, you can create, read, delete, and perform other operations on folders using the following APIs:

Method Description
mkdir / mkdirSync Create folder
readdir / readdirSync Read folder
rmdir / rmdirSync Delete folder
Create Folder

In Node.js, you can use mkdir or mkdirSync to create folders.

Syntax:

  • fs.mkdir(path, [options], callback)
  • fs.mkdirSync(path, [options])

Parameters:

  • path: folder path
  • options: option configuration (optional)
  • callback: callback after operation

Example code:

// 1. Import fs module
const fs = require('fs');

// 2. Create folder
// mkdir make: create directory: directory 
fs.mkdir('./html', error => {
    if (error) {
        console.log('Create directory failed', error)
        return;
    }
    console.log('Create directory successful')
});

// 3. Create folder recursively
fs.mkdir('./a/b/c', {
    recursive: true
}, error => {
    if (error) {
        console.log("Create folder recursively failed", error)
        return;
    }
    console.log('Create folder recursively successful')
});

// 4. Create folder recursively synchronously
fs.mkdirSync('./a/b/c', {recursive: true});
Read Folder

In Node.js, you can use readdir or readdirSync to read folders.

Syntax:

  • fs.readdir(path, [options], callback)
  • fs.readdirSync(path, [options])

Parameters:

  • path: folder path
  • options: option configuration (optional)
  • callback: callback after operation

Example code:

// 1. Import fs module
const fs = require('fs');

// 2. Read folder
// readdir read: read dir:directory directory
fs.readdir('./', (error, data) => {
    if (error) {
        console.log('Read folder error', error)
        return;
    }
    // [
    //     '1-file-write.js',
    //     '2-append-write.js',
    //     '3-stream-write.js',
    //     '4-file-read.js',
    //     '5-stream-read.js',
    //     '6-exercise-file-copy.js',
    //     '7-file-rename-move.js',
    //     '8-delete-file.js',
    //     '9-folder-operation.js',
    //     'a',
    //     'html',
    //     'motto.txt',
    //     'files',
    //     'reading.txt'
    // ]
    console.log(data)
});

// Synchronous read
// let data = fs.readdirSync('./');
// console.log(data);
Delete Folder

In Node.js, you can use rmdir or rmdirSync to delete folders.

Syntax:

  • fs.rmdir(path, [options], callback)
  • fs.rmdirSync(path, [options])

Parameters:

  • path: folder path
  • options: option configuration (optional)
  • callback: callback after operation

Example code:

// 1. Import fs module
const fs = require('fs');

// 2. Delete folder
// fs.rmdir('./files', error => {
//     if (error) {
//         console.log('Delete folder failed', error)
//         return;
//     }
//     console.log('Delete folder successful')
// });

// 3. Delete folder recursively 
// Recursive delete folder failed [Error: ENOTEMPTY: directory not empty, rmdir 'E:\projects\nodejs-basics\a'] 

// Not recommended
// fs.rmdir('./a', {recursive: true}, error => {
//     if (error) {
//         console.log('Recursive delete folder failed', error)
//         return ;
//     }
//     console.log('Recursive delete folder successful')
// });

// Recommended
fs.rm('./a', {recursive: true}, error => {
    if (error) {
        console.log('Recursive delete file failed', error)
        return;
    }
    console.log('Recursive delete file successful')
});

// Synchronous recursive delete folder
fs.rmdirSync('./a', {recursive: true});

Resource Status Check

In Node.js, you can use stat or statSync to view detailed information about resources.

Syntax:

  • fs.stat(path, [options], callback)
  • fs.statSync(path, [options])

Parameters:

  • path: folder path
  • options: option configuration (optional)
  • callback: callback after operation

Example code:

// 1. Import fs module
const fs = require('fs');

// 2. stat method: status abbreviation
fs.stat('./reading.txt', (error, data) => {
    if (error) {
        console.log('Operation failed', error)
        return;
    }
    // Stats {
    //     dev: 985301708,
    //     mode: 33206,
    //     nlink: 1,
    //     uid: 0,
    //     gid: 0,
    //     rdev: 0,
    //     blksize: 4096,
    //     ino: 281474979770305,
    //     size: 92,
    //     blocks: 0,
    //     atimeMs: 1684373309132.9426,
    //     mtimeMs: 1684289136772.1648,
    //     ctimeMs: 1684289136772.1648,
    //     birthtimeMs: 1684289136770.7136,
    //     atime: 2023 - 05 - 18 T01: 28: 29.133 Z,
    //     mtime: 2023 - 05 - 17 T02: 05: 36.772 Z,
    //     ctime: 2023 - 05 - 17 T02: 05: 36.772 Z,
    //     birthtime: 2023 - 05 - 17 T02: 05: 36.771 Z
    // }
    console.log(data)
    console.log(data.isFile())
    console.log(data.isDirectory())
});

// 3. Synchronous status retrieval
let data = fs.statSync('./reading.txt');
console.log(data)
console.log(data.isFile())
console.log(data.isDirectory())

Result value object structure:

  • size: file size
  • birthtime: creation time
  • mtime: last modification time
  • isFile: check if it's a file
  • isDirectory: check if it's a folder

Relative Path Issues

When the fs module operates on resources, there are two ways to write paths:

  • Relative path ./motto.txt: motto.txt in the current directory motto.txt: equivalent to the above writing method ../motto.txt: motto.txt in the parent directory of the current directory
  • Absolute path D:/Program Files: absolute path on Windows system /usr/bin: absolute path on Linux system

The "current directory" in relative paths refers to the command line's working directory, not the directory where the file is located. Therefore, when the command line's working directory doesn't match the file's directory, some bugs may occur.

__dirname

__dirname is similar to require and is a 'global' variable in the Node.js environment. __dirname stores the absolute path of the current file's directory. You can use __dirname to concatenate with filenames to form absolute paths.

Code example:

let data = fs.readFileSync(__dirname + '/data.txt');
console.log(data);

When using the fs module, try to use __dirname to convert paths to absolute paths to avoid bugs caused by relative paths.

Exercise

Implement file copying functionality.

Code example:

/**
 * Requirement:
 *  Copy [motto.txt]
 */

// 1. Import fs module
const fs = require('fs');
// Global object, an attribute of the global object, accessible without declaration. It's an object that describes the current Node process state, providing a simple interface to the operating system.
const process = require('process')

// Method 1: Use readFile
// 2. Read file
// let data = fs.readFileSync('./motto.txt');

// // 3. Write file
// fs.writeFileSync('./motto-2.txt', data);

// // Check system memory usage
// // rss: 19795968 bytes
// console.log(process.memoryUsage())

// Method 2: Use stream operations
// 2. Create stream read
let readStream = fs.createReadStream('./motto.txt');

// 3. Create stream write
let writeStream = fs.createWriteStream('./motto-3.txt');

// // 4. Bind data event
// readStream.on('data', chunk => {
//     writeStream.write(chunk);
// });

// // 5. Bind end event
// readStream.on('end', () => {
//     // rss: 20885504 bytes, which uses less memory compared to synchronous approach
//     console.log(process.memoryUsage())
// });

// 4. Use pipe to directly copy
readStream.pipe(writeStream);

Tags: Node.js Buffer File System fs module Asynchronous Programming

Posted on Mon, 15 Jun 2026 16:04:55 +0000 by maralynnj