# File System Operations: Read Write Delete Files

# File System Operations: Read Write Delete Files - Node.js fs Module

## Problem

Working with files is a fundamental requirement in backend development. Developers need to:
- Read file contents efficiently
- Write data to files (create or overwrite)
- Delete files when no longer needed
- Handle errors gracefully
- Work with both synchronous and asynchronous operations

## Solution

Node.js provides the `fs` (File System) module with methods for all file operations. The recommended approach is using **asynchronous methods** with callbacks, Promises, or async/await to prevent blocking the event loop.

---

## Code Examples

### 1. Reading Files

#### Asynchronous Read (Callback)
```javascript
const fs = require('fs');

fs.readFile('./data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file:', err.message);
    return;
  }
  console.log('File contents:', data);
});
```

#### Asynchronous Read (Promise-based)
```javascript
const fs = require('fs').promises;

async function readFileAsync() {
  try {
    const data = await fs.readFile('./data.txt', 'utf8');
    console.log('File contents:', data);
  } catch (err) {
    console.error('Error reading file:', err.message);
  }
}

readFileAsync();
```

#### Synchronous Read (Blocking - Use Cautiously)
```javascript
const fs = require('fs');

try {
  const data = fs.readFileSync('./data.txt', 'utf8');
  console.log('File contents:', data);
} catch (err) {
  console.error('Error reading file:', err.message);
}
```

---

### 2. Writing Files

#### Asynchronous Write (Callback)
```javascript
const fs = require('fs');

const content = 'Hello, World!\nThis is a test file.';

fs.writeFile('./output.txt', content, 'utf8', (err) => {
  if (err) {
    console.error('Error writing file:', err.message);
    return;
  }
  console.log('File written successfully!');
});
```

#### Asynchronous Write (Promise-based)
```javascript
const fs = require('fs').promises;

async function writeFileAsync() {
  try {
    const content = 'Hello, World!\nThis is a test file.';
    await fs.writeFile('./output.txt', content, 'utf8');
    console.log('File written successfully!');
  } catch (err) {
    console.error('Error writing file:', err.message);
  }
}

writeFileAsync();
```

#### Append to File
```javascript
const fs = require('fs').promises;

async function appendToFile() {
  try {
    const additionalContent = '\nAppended line.';
    await fs.appendFile('./output.txt', additionalContent, 'utf8');
    console.log('Content appended successfully!');
  } catch (err) {
    console.error('Error appending to file:', err.message);
  }
}

appendToFile();
```

---

### 3. Deleting Files

#### Asynchronous Delete (Callback)
```javascript
const fs = require('fs');

fs.unlink('./output.txt', (err) => {
  if (err) {
    console.error('Error deleting file:', err.message);
    return;
  }
  console.log('File deleted successfully!');
});
```

#### Asynchronous Delete (Promise-based)
```javascript
const fs = require('fs').promises;

async function deleteFileAsync() {
  try {
    await fs.unlink('./output.txt');
    console.log('File deleted successfully!');
  } catch (err) {
    console.error('Error deleting file:', err.message);
  }
}

deleteFileAsync();
```

---

### 4. Comprehensive Example: CRUD Operations

```javascript
const fs = require('fs').promises;
const path = require('path');

class FileManager {
  constructor(filePath) {
    this.filePath = filePath;
  }

  // Create/Write file
  async create(content) {
    try {
      await fs.writeFile(this.filePath, content, 'utf8');
      console.log(`✓ File created: ${this.filePath}`);
      return true;
    } catch (err) {
      console.error(`✗ Error creating file: ${err.message}`);
      return false;
    }
  }

  // Read file
  async read() {
    try {
      const data = await fs.readFile(this.filePath, 'utf8');
      console.log(`✓ File read successfully`);
      return data;
    } catch (err) {
      console.error(`✗ Error reading file: ${err.message}`);
      return null;
    }
  }

  // Update/Append to file
  async update(content) {
    try {
      await fs.appendFile(this.filePath, `\n${content}`, 'utf8');
      console.log(`✓ File updated successfully`);
      return true;
    } catch (err) {
      console.error(`✗ Error updating file: ${err.message}`);
      return false;
    }
  }

  // Delete file
  async delete() {
    try {
      await fs.unlink(this.filePath);
      console.log(`✓ File deleted: ${this.filePath}`);
      return true;
    } catch (err) {
      console.error(`✗ Error deleting file: ${err.message}`);
      return false;
    }
  }

  // Check if file exists
  async exists() {
    try {
      await fs.access(this.filePath);
      return true;
    } catch {
      return false;
    }
  }

  // Get file stats
  async getStats() {
    try {
      const stats = await fs.stat(this.filePath);
      return {
        size: stats.size,
        created: stats.birthtime,
        modified: stats.mtime,
        isFile: stats.isFile()
      };
    } catch (err) {
      console.error(`✗ Error getting stats: ${err.message}`);
      return null;
    }
  }
}

// Usage
(async () => {
  const manager = new FileManager('./test.txt');

  // Create
  await manager.create('Initial content');

  // Read
  const content = await manager.read();
  console.log('Content:', content);

  // Update
  await manager.update('Additional line');

  // Get stats
  const stats = await manager.getStats();
  console.log('Stats:', stats);

  // Check existence
  const exists = await manager.exists();
  console.log('File exists:', exists);

  // Delete
  await manager.delete();
})();
```

---

### 5. Working with JSON Files

```javascript
const fs = require('fs').promises;

class JSONFileManager {
  constructor(filePath) {
    this.filePath = filePath;
  }

  async readJSON() {
    try {
      const data = await fs.readFile(this.filePath, 'utf8');
      return JSON.parse(data);
    } catch (err) {
      console.error('Error reading JSON:', err.message);
      return null;
    }
  }

  async writeJSON(obj) {
    try {
      const jsonString = JSON.stringify(obj, null, 2);
      await fs.writeFile(this.filePath, jsonString, 'utf8');
      console.log('JSON file written successfully');
      return true;
    } catch (err) {
      console.error('Error writing JSON:', err.message);
      return false;
    }
  }

  async updateJSON(updates) {
    try {
      const data = await this.readJSON();
      const merged = { ...data, ...updates };
      await this.writeJSON(merged);
      console.log('JSON file updated successfully');
      return true;
    } catch (err) {
      console.error('Error updating JSON:', err.message);
      return false;
    }
  }
}

// Usage
(async () => {
  const jsonManager = new JSONFileManager('./config.json');

  // Write
  await jsonManager.writeJSON({ 
    name: 'MyApp', 
    version: '1.0.0',
    debug: true 
  });

  // Read
  const config = await jsonManager.readJSON();
  console.log('Config:', config);

  // Update
  await jsonManager.updateJSON({ debug: false, version: '1.1.0' });
})();
```

---

## Key Takeaways

| Operation | Method | Async | Blocking |
|-----------|--------|-------|----------|
| Read | `readFile()` | ✓ | ✗ |
| Write | `writeFile()` | ✓ | ✗ |
| Append | `appendFile()` | ✓ | ✗ |
| Delete | `unlink()` | ✓ | ✗ |
| Exists | `access()` | ✓ | ✗ |
| Stats | `stat()` | ✓ | ✗ |

**Best Practices:**
- Always use async methods to prevent blocking
- Use `fs.promises` or async/await for cleaner code
- Handle errors with try/catch blocks
- Check file existence before operations
- Use appropriate encoding (usually 'utf8')
- Consider file permissions and access rights
