Get your own Node server
const fs = require('fs');
const path = require('path');

// Function to create and handle a ReadStream with proper error handling
function readWithErrorHandling(filePath) {
  console.log(`Attempting to read: ${filePath}`);
  
  // Create the ReadStream
  const readStream = fs.createReadStream(filePath);
  
  // Set up promise to capture result or error
  return new Promise((resolve, reject) => {
    let data = '';
    
    // Handle data events
    readStream.on('data', (chunk) => {
      data += chunk;
    });
    
    // Handle successful completion
    readStream.on('end', () => {
      console.log(`Successfully read ${readStream.bytesRead} bytes from ${filePath}`);
      resolve(data);
    });
    
    // Handle errors
    readStream.on('error', (err) => {
      console.error(`Error reading ${filePath}: ${err.message}`);
      reject(err);
    });
    
    // Handle stream closure (always happens, even if there's an error)
    readStream.on('close', () => {
      console.log(`Stream for ${filePath} closed`);
    });
  });
}

// Test with both existing and non-existing files
const existingFile = path.join(__dirname, 'test-existing.txt');
const nonExistingFile = path.join(__dirname, 'non-existing-file.txt');

// Create the test file
fs.writeFileSync(existingFile, 'This is test content for error handling example');

// Example 1: Reading an existing file
console.log('Example 1: Reading an existing file');
readWithErrorHandling(existingFile)
  .then(data => {
    console.log('File content:', data);
    
    // Example 2: Reading a non-existing file
    console.log('\nExample 2: Reading a non-existing file');
    return readWithErrorHandling(nonExistingFile);
  })
  .catch(err => {
    console.log('Error caught in Promise catch:', err.message);
  })
  .finally(() => {
    // Clean up the test file
    if (fs.existsSync(existingFile)) {
      fs.unlinkSync(existingFile);
      console.log('Test file removed');
    }
  });

// Example 3: Demonstrating destroyed streams
console.log('\nExample 3: Demonstrating destroyed streams');
const destroyTestFile = path.join(__dirname, 'destroy-test.txt');
fs.writeFileSync(destroyTestFile, 'A'.repeat(10000));

const destroyStream = fs.createReadStream(destroyTestFile);

destroyStream.on('data', (chunk) => {
  console.log(`Received ${chunk.length} bytes before destroying the stream`);
  
  // Destroy the stream after receiving the first chunk
  console.log('Deliberately destroying the stream');
  destroyStream.destroy(new Error('Stream manually destroyed'));
});

destroyStream.on('error', (err) => {
  console.error(`Destruction error: ${err.message}`);
});

destroyStream.on('close', () => {
  console.log('Destroyed stream closed');
  
  // Clean up
  fs.unlinkSync(destroyTestFile);
  console.log('Destroy test file removed');
});

              
Example 1: Reading an existing file
----------------------------------
Attempting to read: /path/to/test-existing.txt
Stream for /path/to/test-existing.txt closed
Successfully read 50 bytes from /path/to/test-existing.txt
File content: This is test content for error handling example

Example 2: Reading a non-existing file
------------------------------------
Attempting to read: /path/to/non-existing-file.txt
Error reading /path/to/non-existing-file.txt: ENOENT: no such file or directory, open '/path/to/non-existing-file.txt'
Stream for /path/to/non-existing-file.txt closed
Error caught in Promise catch: ENOENT: no such file or directory, open '/path/to/non-existing-file.txt'

Example 3: Demonstrating stream destruction
-----------------------------------------
Received 65536 bytes before destroying the stream
Deliberately destroying the stream
Destruction error: Stream manually destroyed
Destroyed stream closed
Destroy test file removed
Test file removed