# Sistema de Archivos de Node.js
El módulo `fs` (file system) de Node.js proporciona una API para interactuar con el sistema de archivos. Aprende a leer, escribir, actualizar y eliminar archivos y directorios.
## Módulo fs
Node.js proporciona métodos síncronos y asíncronos para operaciones de archivos:
```javascript
// CommonJS
const fs = require('fs');
// ES Modules
import fs from 'fs';
// API de Promises (recomendado)
import fs from 'fs/promises';
```
## Lectura de Archivos
### Síncrono (Bloquea el Hilo)
```javascript
const fs = require('fs');
try {
// Leer archivo completo
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('Error al leer archivo:', err);
}
```
### Asíncrono con Callbacks
```javascript
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error al leer archivo:', err);
return;
}
console.log(data);
});
console.log('Este mensaje aparece primero');
```
### Asíncrono con Promises (Recomendado)
```javascript
const fs = require('fs/promises');
async function readFile() {
try {
const data = await fs.readFile('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('Error al leer archivo:', err);
}
}
readFile();
```
### Leyendo Archivos JSON
```javascript
const fs = require('fs/promises');
async function readJSON() {
try {
const data = await fs.readFile('data.json', 'utf8');
const json = JSON.parse(data);
console.log(json);
} catch (err) {
console.error('Error:', err);
}
}
// O más simple:
async function readJSON2() {
const json = JSON.parse(
await fs.readFile('data.json', 'utf8')
);
return json;
}
```
## Escritura de Archivos
### Escribir Archivo Completo
```javascript
const fs = require('fs/promises');
async function writeFile() {
try {
await fs.writeFile('output.txt', '¡Hola, Mundo!', 'utf8');
console.log('¡Archivo escrito exitosamente!');
} catch (err) {
console.error('Error al escribir archivo:', err);
}
}
```
### Agregar a Archivo
```javascript
const fs = require('fs/promises');
async function appendFile() {
try {
await fs.appendFile('log.txt', 'Nueva línea de log
', 'utf8');
console.log('¡Contenido agregado!');
} catch (err) {
console.error('Error:', err);
}
}
```
### Escribir Archivos JSON
```javascript
const fs = require('fs/promises');
async function writeJSON() {
const data = {
nombre: 'Juan',
edad: 30,
ciudad: 'Madrid'
};
try {
await fs.writeFile(
'user.json',
JSON.stringify(data, null, 2),
'utf8'
);
console.log('¡JSON guardado!');
} catch (err) {
console.error('Error:', err);
}
}
```
## Trabajando con Directorios
### Crear Directorio
```javascript
const fs = require('fs/promises');
async function createDir() {
try {
// Crear directorio único
await fs.mkdir('nuevo-dir');
// Crear directorios anidados
await fs.mkdir('ruta/a/directorio', { recursive: true });
console.log('¡Directorios creados!');
} catch (err) {
console.error('Error:', err);
}
}
```
### Leer Contenidos del Directorio
```javascript
const fs = require('fs/promises');
async function listFiles() {
try {
const files = await fs.readdir('.');
console.log('Archivos:', files);
// Con información de tipo de archivo
const entries = await fs.readdir('.', { withFileTypes: true });
entries.forEach(entry => {
console.log(
entry.name,
entry.isDirectory() ? '(directorio)' : '(archivo)'
);
});
} catch (err) {
console.error('Error:', err);
}
}
```
### Eliminar Directorio
```javascript
const fs = require('fs/promises');
async function removeDir() {
try {
// Eliminar directorio vacío
await fs.rmdir('empty-dir');
// Eliminar directorio con contenidos
await fs.rm('dir-with-files', { recursive: true, force: true });
console.log('¡Directorios eliminados!');
} catch (err) {
console.error('Error:', err);
}
}
```
## Información de Archivos
### Obtener Estadísticas de Archivo
```javascript
const fs = require('fs/promises');
async function getFileInfo() {
try {
const stats = await fs.stat('file.txt');
console.log('¿Es archivo?', stats.isFile());
console.log('¿Es directorio?', stats.isDirectory());
console.log('Tamaño:', stats.size, 'bytes');
console.log('Creado:', stats.birthtime);
console.log('Modificado:', stats.mtime);
console.log('Accedido:', stats.atime);
} catch (err) {
console.error('Error:', err);
}
}
```
### Verificar si Existe Archivo
```javascript
const fs = require('fs/promises');
async function fileExists(path) {
try {
await fs.access(path);
return true;
} catch {
return false;
}
}
// Usar
if (await fileExists('file.txt')) {
console.log('¡El archivo existe!');
}
```
## Copiar y Mover Archivos
### Copiar Archivo
```javascript
const fs = require('fs/promises');
async function copyFile() {
try {
await fs.copyFile('source.txt', 'destination.txt');
console.log('¡Archivo copiado!');
} catch (err) {
console.error('Error:', err);
}
}
```
### Mover/Renombrar Archivo
```javascript
const fs = require('fs/promises');
async function moveFile() {
try {
// Renombrar en mismo directorio
await fs.rename('old-name.txt', 'new-name.txt');
// Mover a diferente directorio
await fs.rename('file.txt', 'carpeta/file.txt');
console.log('¡Archivo movido!');
} catch (err) {
console.error('Error:', err);
}
}
```
### Eliminar Archivo
```javascript
const fs = require('fs/promises');
async function deleteFile() {
try {
await fs.unlink('file-to-delete.txt');
console.log('¡Archivo eliminado!');
} catch (err) {
console.error('Error:', err);
}
}
```
## Módulo Path
El módulo `path` ayuda a trabajar con rutas de archivo y directorio:
```javascript
const path = require('path');
// Unir rutas
const filePath = path.join(__dirname, 'data', 'users.json');
// /Users/usuario/proyecto/data/users.json
// Resolver ruta absoluta
const absolute = path.resolve('data', 'file.txt');
// Obtener extensión
const ext = path.extname('file.txt'); // .txt
// Obtener nombre de archivo
const filename = path.basename('/ruta/a/file.txt'); // file.txt
// Obtener directorio
const dir = path.dirname('/ruta/a/file.txt'); // /ruta/a
// Análisis de ruta
const parsed = path.parse('/ruta/a/file.txt');
// {
// root: '/',
// dir: '/ruta/a',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
// Normalizar ruta
const normalized = path.normalize('/ruta//a/./file.txt');
// /ruta/a/file.txt
```
## Ejemplo Práctico: Sistema de Gestión de Archivos
```javascript
const fs = require('fs/promises');
const path = require('path');
class FileManager {
constructor(baseDir) {
this.baseDir = baseDir;
}
// Asegurar que el directorio base existe
async init() {
await fs.mkdir(this.baseDir, { recursive: true });
}
// Guardar datos JSON
async saveJSON(filename, data) {
const filePath = path.join(this.baseDir, filename);
await fs.writeFile(
filePath,
JSON.stringify(data, null, 2),
'utf8'
);
}
// Leer datos JSON
async readJSON(filename) {
const filePath = path.join(this.baseDir, filename);
const data = await fs.readFile(filePath, 'utf8');
return JSON.parse(data);
}
// Listar todos los archivos
async listFiles() {
const entries = await fs.readdir(this.baseDir, {
withFileTypes: true
});
return entries
.filter(entry => entry.isFile())
.map(entry => entry.name);
}
// Eliminar archivo
async deleteFile(filename) {
const filePath = path.join(this.baseDir, filename);
await fs.unlink(filePath);
}
// Obtener información de archivo
async getFileInfo(filename) {
const filePath = path.join(this.baseDir, filename);
const stats = await fs.stat(filePath);
return {
nombre: filename,
tamaño: stats.size,
creado: stats.birthtime,
modificado: stats.mtime,
esDirectorio: stats.isDirectory()
};
}
}
// Usar
async function main() {
const fm = new FileManager('./data');
await fm.init();
// Guardar datos
await fm.saveJSON('users.json', [
{ id: 1, nombre: 'Juan' },
{ id: 2, nombre: 'María' }
]);
// Leer datos
const users = await fm.readJSON('users.json');
console.log('Usuarios:', users);
// Listar archivos
const files = await fm.listFiles();
console.log('Archivos:', files);
// Obtener información
const info = await fm.getFileInfo('users.json');
console.log('Info:', info);
}
main().catch(console.error);
```
## Manejo de Errores
Siempre maneja errores al trabajar con el sistema de archivos:
```javascript
const fs = require('fs/promises');
async function safeReadFile(filename) {
try {
const data = await fs.readFile(filename, 'utf8');
return { success: true, data };
} catch (err) {
if (err.code === 'ENOENT') {
return { success: false, error: 'Archivo no encontrado' };
}
if (err.code === 'EACCES') {
return { success: false, error: 'Permiso denegado' };
}
return { success: false, error: err.message };
}
}
// Usar
const result = await safeReadFile('file.txt');
if (result.success) {
console.log(result.data);
} else {
console.error(result.error);
}
```
### Códigos de Error Comunes
| Código | Significado |
|--------|------------|
| `ENOENT` | No existe tal archivo o directorio |
| `EACCES` | Permiso denegado |
| `EEXIST` | El archivo ya existe |
| `EISDIR` | Es un directorio |
| `ENOTDIR` | No es un directorio |
## Mejores Prácticas
1. **Usar Async/Await**: Preferir métodos asíncronos sobre síncronos
2. **Manejo de Errores**: Siempre usar try/catch con async/await
3. **Usar path.join()**: Para rutas multi-plataforma
4. **Validar Rutas**: Verificar la existencia de archivos antes de operaciones
5. **Streams para Archivos Grandes**: Usar streams para archivos grandes
6. **Cerrar Descriptores de Archivo**: Limpiar después de operaciones
## Recursos
- [Documentación de fs](https://nodejs.org/docs/latest/api/fs.html)
- [Documentación de path](https://nodejs.org/docs/latest/api/path.html)
¡Domina las operaciones de archivos en Node.js! 📁
Lección 3 de 6
7 min de lectura
Node.js
Sistema de Archivos de Node.js
Trabajar con archivos y directorios en Node.js