隆Estamos en directo en Twitch!

隆Entra y participa!

Imagen de la etiqueta node

C贸mo eliminar un fichero con Node.js

6 minutos de lectura驴Una errata? Edita el art铆culo

En ocasiones necesitamos eliminar un fichero de nuestro sistema de forma program谩tica utilizando Node.js. Muchas veces vamos directos a buscar un paquete en npm (que los hay y muy buenos como del) que nos solucione la papeleta pero Node.js incorpora una forma nativa de eliminar ficheros y enlaces simb贸licos a ficheros con muy poco esfuerzo. Y creo que puede ser interesante aprenderlo.

Para eliminar un fichero en Node.js podemos usar el m贸dulo fs que tiene dos m茅todos que nos ayudar谩n a conseguirlo: fs.unlink() y fs.unlinkSync().

La diferencia es que el primero no bloquear谩 el hilo principal, ya que realiza la operaci贸n de forma as铆ncrona, mientras que el segundo esperar谩 a que termine la operaci贸n antes de seguir ejecutando el c贸digo que le sigue. Huelga decir que, siempre que podamos, tendr铆amos que usar el primero.

Usando fs.unlinkSync, que ser铆a de forma s铆ncrona:

// importa el m贸dulo de node `file-system`
const fs = require('fs')

try {
  fs.unlinkSync('./old-article.md')
  console.log('File removed')
} catch(err) {
  console.error('Something wrong happened removing the file', err)
}

Usando fs.unlink, que ser铆a as铆ncrono:

// importa el m贸dulo de node `file-system`
const fs = require('fs').promises

fs.unlink('./old-article.md')
  .then(() => {
    console.log('File removed')
  }).catch(err => {
    console.error('Something wrong happened removing the file', err)
  })

C贸mo conseguir eliminar el fichero con Promesas

Desde Node.js 10, tambi茅n puedes utilizar la versi贸n de fs.unlink que devuelve una Promesa. Para ello, s贸lo tienes que requerir el m贸dulo fs pero accediendo a la propiedad promises.

// importa el subm贸dulo `promises` del m贸dulo de node `file-system`
const fs = require('fs').promises

fs.unlink('./old-article.md')
  .then(() => {
    console.log('File removed')
  }).catch(err => {
    console.error('Something wrong happened removing the file', err)
  })

// o con async/await ser铆a de la siguiente forma:
;(async () => {
  try {
    await fs.unlink('./old-article.md')
    console.log('File removed')
  } catch(err) {
    console.error('Something wrong happened removing the file', err)
  }
})()

C贸mo eliminar m谩s de un fichero a la vez con Node.js

Vale, el ejemplo anterior funciona… pero es muy b谩sico, ya que s贸lo nos permite eliminar un fichero a la vez y, en ocasiones, queremos eliminar una lista de ficheros.

Usando un Promise.all

Ser铆a muy sencillo basarnos en el ejemplo anterior para poder borrar m谩s de un fichero gracias al uso de Promise.all:

const fs = require('fs').promises

const files = [
  './articles/old-article.md',
  './articles/old-article2.md',
  './articles/old-article3.md',
]

Promise.all(files.map(file => fs.unlink(file)))
  .then(() => {
    console.log('All files removed')
  })
  .catch(err => {
    console.error('Something wrong happened removing files', err)
  })

Eliminando los ficheros de un directorio

Por ejemplo, si tuvieramos una carpeta /images y quisieramos borrar todos los ficheros dentro, podr铆amos usar el m茅todo fs.readdir para leer los ficheros de un directorio y el path.join para tener el path correcto para nuestro sistema para el fichero. De esta forma:

const fs = require('fs').promises
const path = require('path')
const FOLDER_TO_REMOVE = 'images'

fs.readdir(FOLDER_TO_REMOVE)
  .then(files => {
    const unlinkPromises = files.map(file => {
      const filePath = path.join(FOLDER_TO_REMOVE, file)
      return fs.unlink(filePath)
    })

    return Promise.all(unlinkPromises)
  }).catch(err => {
    console.error(`Something wrong happened removing files of ${FOLDER_TO_REMOVE}`)
  })

La soluci贸n anterior funciona en el caso que el directorio no tenga, a su vez, otros directorios. De lo contrario, nos dar谩 un error Error: EPERM: operation not permitted, unlink 'images/sub-folder'.

Para ignorar los directorios, podr铆amos hacer una peque帽a utilidad que nos ayudase a detectarlos:

async function checkIsDirectory (path) {
  const stats = await fs.lstat(path)
  return stats.isDirectory()
}

Y entonces utilizamos ese m茅todo para que, si es un directorio, no hagamos nada con ese path.

fs.readdir(FOLDER_TO_REMOVE)
  .then(files => {
    const unlinkPromises = files.map(async file => { // a帽adimos async
      const filePath = path.join(FOLDER_TO_REMOVE, file)
      const isDirectory = await checkIsDirectory(filePath)
      return isDirectory ? Promise.resolve() : fs.unlink(filePath)
    })

    return Promise.all(unlinkPromises)
  }).catch(err => {
    console.error(`Something wrong happened removing files of ${FOLDER_TO_REMOVE}`)
  })

Eliminado un directorio de forma recursiva

驴Y qu茅 pasa si quiero eliminar tambi茅n los subdirectorios de ese directorio? Bueno, si est谩s utilizando la versi贸n Node.js 12.10.0 o superior, puedes utilizar directamente el m茅todo fs.rmdir y la opci贸n recursive el directorio de forma recursiva (esto no s贸lo eliminar谩 los ficheros de dentro si no tambi茅n todos sus subdirectorios).

const fs = require('fs').promises

fs.rmdir('./articles', { recursive: true })
  .then(() => {
    console.log('"articles" folder removed')
  })
  .catch(err => {
    console.error('Something wrong happened removing "articles" folder', err)
  })

A la hora de escribir este art铆culo, la opci贸n recursive est谩 en modo experimental y puede no ser estable.

Eliminar ficheros buscando un pattern

Otra opci贸n ser铆a utilizar una librer铆a como globby para poder borrar archivos de forma m谩s granular. Por ejemplo, pongamos que tenemos una carpeta de im谩genes con esta estructura:

鈹溾攢鈹 images
鈹溾攢鈹鈹鈹  image000.png
鈹溾攢鈹鈹鈹  old-image000.png
鈹溾攢鈹鈹鈹  old-image001.jpg
鈹溾攢鈹鈹鈹  ...
鈹溾攢鈹鈹鈹  old-image400.gif

Y queremos eliminar todos los ficheros que tienen extensi贸n .jpg y que, adem谩s, son im谩genes antiguas por lo que su nombre comienza con old-image. Entonces, podr铆amos hacer lo siguiente:

const globby = require('globby')
const fs = require('fs').promises

globby('./images/old-image*.jpg')
  .then(files => {
    const deletePromises = files.map(file => fs.unlink(file))
    return Promise.all(deletePromises)
  })
  .then(() => {
    console.log('All files removed')
  })
  .catch(err => {
    console.error('Something wrong happened removing files', err)
  })

Al final, aqu铆 podr铆amos usar cualquier patr贸n (o lista de patrones) que queramos buscar. Usando la documentaci贸n de globby puedes encontrar diferentes posibilidades, como usar ! al principio de un pattern para negar la b煤squeda o usar expresiones OR con {}.

C贸mo mover ficheros a la papelera con Node.js

Los ejemplos anteriores eliminan de forma definitiva los ficheros. Y muchas veces tiene sentido pero, en ocasiones, lo que queremos en realidad, es simplemente dejar los ficheros en la Papelera de Reciclaje de nuestro sistema operativo para decidir m谩s tarde qu茅 hacemos con ellos.

Para eso, podemos utilizar el paquete trash que soporta los sistemas operativos macOS (10.12+), Linux y Windows (8+).

Para ello, tendremos que importar la utilidad y pasarle como par谩metro el path o el pattern que tiene que buscar para mover a la papelera esos ficheros. Tambi茅n puedes pasarle un Array con m谩s de un path o pattern. Adem谩s, la operaci贸n es as铆ncrona y devuelve una promesa.

const trash = require('trash')

// elimina todos los archivos que terminan en .md
// excepto el que se llama articulo.md
trash(['*.md', '!articulo.png']).then(() => {
  console.log('Files moved to Trash!')
})

// o con async/await ser铆a de la siguiente forma:
;(async () => {
  await trash(['*.md', '!articulo.png'])
  console.log('Files moved to Trash!')
})()

El pattern (patr贸n) que le puedes pasar est谩 basado en glob pattern. Igual que en el ejemplo anterior. Puedes encontrar una lista de patrones aceptados aqu铆: https://github.com/sindresorhus/globby#globbing-patterns

Conclusiones

Como dec铆a al principio, es verdad que paquetes como del nos soluciona directamente mucho de los problemas que hemos visto anteriormente pero creo que es importante conocer las posibilidades nativas que nos da Node.js y que, a veces, puede ser interesante no tener una dependencia para ciertas operaciones. Si estabas buscando c贸mo puedes eliminar ficheros y directorios en Node.js espero que este art铆culo te haya servido. A mi me ha valido para repasar. :)

Contenido del art铆culo

Comparte el art铆culo