Guía de Node.js, Parte 9: Trabajar con el sistema de archivos

Hoy, en la novena parte de la traducción del tutorial Node.js, hablaremos sobre trabajar con archivos. En particular, hablaremos sobre fs y módulos de ruta: sobre descriptores de archivos, sobre rutas de archivos, sobre cómo obtener información sobre archivos, sobre cómo leerlos y escribirlos, sobre cómo trabajar con directorios.




Trabajar con descriptores de archivo en Node.js


Antes de poder interactuar con los archivos ubicados en el sistema de archivos de su servidor, necesita obtener un descriptor de archivo.

El descriptor se puede obtener utilizando el método asincrónico open() del módulo fs para abrir el archivo:

 const fs = require('fs') fs.open('/Users/flavio/test.txt', 'r', (err, fd) => { //fd -    }) 

Tenga en cuenta el segundo parámetro, r , utilizado al llamar al método fs.open() . Esta es una bandera que le dice al sistema que el archivo se está abriendo para leer. Aquí hay algunos indicadores más que a menudo se usan cuando se trabaja con este y otros métodos:

  • r+ : abre el archivo para leer y escribir.
  • w+ : abre el archivo para leerlo y escribirlo configurando el puntero de flujo al comienzo del archivo. Si el archivo no existe, se crea.
  • a : abra el archivo para escribirlo configurando el puntero de flujo al final del archivo. Si el archivo no existe, se crea.
  • a+ : abre el archivo para leer y escribir configurando el puntero de flujo al final del archivo. Si el archivo no existe, se crea.

Los archivos se pueden abrir utilizando el método síncrono fs.openSync() , que, en lugar de proporcionar un descriptor de archivo en la devolución de llamada, lo devuelve:

 const fs = require('fs') try { const fd = fs.openSync('/Users/flavio/test.txt', 'r') } catch (err) { console.error(err) } 

Después de recibir el descriptor utilizando cualquiera de los métodos anteriores, puede realizar las operaciones necesarias con él.

Datos de archivo


Cada archivo tiene un conjunto de datos asociado; puede examinar estos datos utilizando Node.js. En particular, esto se puede hacer usando el método stat() del módulo fs .

Se llama a este método, pasándole la ruta al archivo y, después de que Node.js recibe la información necesaria sobre el archivo, llamará a la devolución de llamada pasada al método stat() . Así es como se ve:

 const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) {   console.error(err)   return } //      `stats` }) 

Node.js tiene la capacidad de recuperar sincrónicamente la información del archivo. Con este enfoque, el hilo principal se bloquea hasta que se obtienen las propiedades del archivo:

 const fs = require('fs') try { const stats = fs.statSync ('/Users/flavio/test.txt') } catch (err) { console.error(err) } 

La información sobre el archivo caerá en la constante de stats . ¿Qué es esta información? De hecho, el objeto correspondiente nos proporciona una gran cantidad de propiedades y métodos útiles:

  • Los .isFile() y .isDirectory() permiten, respectivamente, averiguar si el archivo investigado es un archivo o directorio normal.
  • El método .isSymbolicLink() permite saber si un archivo es un enlace simbólico.
  • El tamaño del archivo se puede encontrar usando la propiedad .size .

Hay otros métodos aquí, pero estos son los más utilizados. Aquí se explica cómo usarlos:

 const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) {   console.error(err)   return } stats.isFile() //true stats.isDirectory() //false stats.isSymbolicLink() //false stats.size //1024000 //= 1MB }) 

Rutas de archivo en Node.js y el módulo de ruta


La ruta del archivo es la dirección del lugar en el sistema de archivos donde se encuentra.

En Linux y macOS, la ruta podría verse así:

 /users/flavio/file.txt 

En Windows, las rutas se ven un poco diferentes:

 C:\users\flavio\file.txt 

Deben observarse las diferencias en los formatos de grabación de rutas cuando se utilizan diferentes sistemas operativos, dado el sistema operativo utilizado para implementar el servidor Node.js.

Node.js tiene un módulo de path estándar diseñado para trabajar con rutas de archivo. Antes de usar este módulo en un programa, debe estar conectado:

 const path = require('path') 

▍ Obtención de información de ruta de archivo


Si tiene una ruta al archivo, entonces, utilizando las capacidades del módulo de path , puede, en una forma conveniente para la percepción y el procesamiento posterior, encontrar detalles sobre esta ruta. Se ve así:

 const notes = '/users/flavio/notes.txt' path.dirname(notes) // /users/flavio path.basename(notes) // notes.txt path.extname(notes) // .txt 

Aquí, en la línea de notes , se almacena la ruta del archivo. Los siguientes métodos del módulo de path se utilizaron para analizar la path :

  • dirname() : devuelve el directorio principal del archivo.
  • basename() : devuelve el nombre del archivo.
  • extname() : devuelve la extensión del archivo.

Puede encontrar el nombre del archivo sin la extensión llamando al método .basename() y pasándole el segundo argumento que representa la extensión:

 path.basename(notes, path.extname(notes)) //notes 

▍Trabajo con rutas de archivo


Se pueden combinar varias partes de la ruta utilizando el método path.join() :

 const name = 'flavio' path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 

Puede encontrar la ruta absoluta al archivo en función de la ruta relativa al mismo utilizando el método path.resolve() :

 path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'       

En este caso, Node.js simplemente agrega /flavio.txt a la ruta que conduce al directorio de trabajo actual. Si, al llamar a este método, pasa otro parámetro que representa la ruta a la carpeta, el método lo utiliza como base para determinar la ruta absoluta:

 path.resolve('tmp', 'flavio.txt') // '/Users/flavio/tmp/flavio.txt'       

Si la ruta pasada como el primer parámetro comienza con una barra diagonal, esto significa que es una ruta absoluta.

 path.resolve('/etc', 'flavio.txt') // '/etc/flavio.txt' 

Aquí hay otro método útil: path.normalize() . Le permite encontrar la ruta real al archivo utilizando la ruta que contiene los calificadores de ruta relativos como un punto ( . ), Dos puntos ( .. ) o dos barras:

 path.normalize('/users/flavio/..//test.txt') // /users/test.txt 

Los métodos resolve() y normalize() no verifican la existencia de un directorio. Simplemente encuentran la ruta en función de los datos que se les pasan.

Lectura de archivos en Node.js


La forma más fácil de leer archivos en Node.js es usar el método fs.readFile() , pasándole la ruta al archivo y la devolución de llamada, que se llamará con la transferencia de los datos del archivo (o el objeto de error):

 fs.readFile('/Users/flavio/test.txt', (err, data) => { if (err) {   console.error(err)   return } console.log(data) }) 

Si es necesario, puede usar la versión síncrona de este método: fs.readFileSync() :

 const fs = require('fs') try { const data = fs.readFileSync('/Users/flavio/test.txt') console.log(data) } catch (err) { console.error(err) } 

Por defecto, la codificación utf8 se usa al leer archivos, pero la codificación también se puede configurar de forma independiente al pasar el parámetro apropiado al método.

Los fs.readFile() y fs.readFileSync() leen todo el contenido del archivo en la memoria. Esto significa que trabajar con archivos grandes utilizando estos métodos afectará seriamente el consumo de memoria de su aplicación y afectará su rendimiento. Si necesita trabajar con dichos archivos, es mejor usar transmisiones.

Escribir archivos en Node.js


En Node.js, es más fácil escribir archivos usando el método fs.writeFile() :

 const fs = require('fs') const content = 'Some content!' fs.writeFile('/Users/flavio/test.txt', content, (err) => { if (err) {   console.error(err)   return } //   }) 

También hay una versión síncrona del mismo método: fs.writeFileSync() :

 const fs = require('fs') const content = 'Some content!' try { const data = fs.writeFileSync('/Users/flavio/test.txt', content) //   } catch (err) { console.error(err) } 

Estos métodos, por defecto, reemplazan el contenido de los archivos existentes. Puede cambiar su comportamiento estándar utilizando el indicador apropiado:

 fs.writeFile('/Users/flavio/test.txt', content, { flag: 'a+' }, (err) => {}) 

Aquí se pueden usar banderas, que ya hemos enumerado en la sección de descriptores. Los detalles sobre las banderas se pueden encontrar aquí .

Adjuntar datos a un archivo


El método fs.appendFile() (y su versión síncrona, fs.appendFileSync() ) se usa convenientemente para adjuntar datos al final del archivo:

 const content = 'Some content!' fs.appendFile('file.log', content, (err) => { if (err) {   console.error(err)   return } //! }) 

Sobre el uso de hilos


Anteriormente, describimos métodos que, al escribir en un archivo, escriben la cantidad total de datos transferidos a él, después de lo cual, si se usan sus versiones síncronas, devuelven el control al programa, y ​​si se usan versiones asíncronas, llaman a devoluciones de llamada. Si este estado de cosas no le conviene, sería mejor usar transmisiones.

Trabajando con directorios en Node.js


El módulo fs proporciona al desarrollador muchos métodos convenientes que se pueden usar para trabajar con directorios.

▍Compruebe la existencia de carpetas


Para verificar si el directorio existe y si Node.js puede acceder a él, dados los permisos, puede usar el método fs.access() .

▍ Crear una nueva carpeta


Para crear nuevas carpetas, puede usar los fs.mkdir() y fs.mkdirSync() :

 const fs = require('fs') const folderName = '/Users/flavio/test' try { if (!fs.existsSync(dir)){   fs.mkdirSync(dir) } } catch (err) { console.error(err) } 

▍Leer el contenido de la carpeta


Para leer el contenido de una carpeta, puede usar los fs.readdir() y fs.readdirSync() . Este ejemplo lee el contenido de la carpeta, es decir, la información sobre qué archivos y subdirectorios contiene y devuelve sus rutas relativas:

 const fs = require('fs') const path = require('path') const folderPath = '/Users/flavio' fs.readdirSync(folderPath) 

Así es como puede obtener la ruta completa al archivo:

 fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName) } 

Los resultados se pueden filtrar para obtener solo los archivos y excluirlos de la salida del directorio:

 const isFile = fileName => { return fs.lstatSync(fileName).isFile() } fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName)).filter(isFile) } 

▍ Cambiar nombre de carpeta


Puede usar los fs.rename() y fs.renameSync() para cambiar el nombre de la carpeta. El primer parámetro es la ruta de la carpeta actual, el segundo es uno nuevo:

 const fs = require('fs') fs.rename('/Users/flavio', '/Users/roger', (err) => { if (err) {   console.error(err)   return } // }) 

Puede cambiar el nombre de la carpeta utilizando el método síncrono fs.renameSync() :

 const fs = require('fs') try { fs.renameSync('/Users/flavio', '/Users/roger') } catch (err) { console.error(err) } 

▍ Eliminar carpeta


Para eliminar una carpeta, puede usar los fs.rmdir() o fs.rmdirSync() . Cabe señalar que eliminar una carpeta en la que hay algo es una tarea un poco más complicada que eliminar una carpeta vacía. Si necesita eliminar tales carpetas, use el paquete fs-extra , que es muy popular y está bien soportado. Es un reemplazo para el módulo fs , ampliando sus capacidades.

El método remove() del paquete fs-extra puede eliminar carpetas que ya tienen algo.

Puede instalar este módulo de la siguiente manera:

 npm install fs-extra 

Aquí hay un ejemplo de su uso:

 const fs = require('fs-extra') const folder = '/Users/flavio' fs.remove(folder, err => { console.error(err) }) 

Sus métodos se pueden usar en forma de promesas:

 fs.remove(folder).then(() => { // }).catch(err => { console.error(err) }) 

La construcción asíncrona / espera también es aceptable:

 async function removeFolder(folder) { try {   await fs.remove(folder)   // } catch (err) {   console.error(err) } } const folder = '/Users/flavio' removeFolder(folder) 

Módulo fs


Arriba, ya hemos encontrado algunos métodos del módulo fs que se usan cuando se trabaja con el sistema de archivos. De hecho, contiene muchas más cosas útiles. Recuerde que no necesita ser instalado, para usarlo en el programa, es suficiente para conectarlo:

 const fs = require('fs') 

Después de eso, tendrá acceso a sus métodos, entre los cuales destacamos los siguientes, algunos de los cuales ya conoce:

  • fs.access() : comprueba la existencia de un archivo y la capacidad de acceder a él en función de los permisos.
  • fs.appendFile() : fs.appendFile() datos a un archivo. Si el archivo no existe, se creará.
  • fs.chmod() : cambia los permisos para un archivo dado. Métodos similares: fs.lchmod() , fs.fchmod() .
  • fs.chown() : cambia el propietario y el grupo para el archivo dado. Métodos similares: fs.fchown() , fs.lchown() .
  • fs.close() : cierra el descriptor de archivo.
  • fs.copyFile() : copia el archivo.
  • fs.createReadStream() : crea una secuencia para leer un archivo.
  • fs.createWriteStream() : crea una secuencia de escritura de archivos.
  • fs.link() : crea un nuevo enlace duro al archivo.
  • fs.mkdir() : crea un nuevo directorio.
  • fs.mkdtemp() : crea un directorio temporal.
  • fs.open() : abre un archivo.
  • fs.readdir() : lee el contenido de un directorio.
  • fs.readFile() : lee el contenido de un archivo. Método similar: fs.read() .
  • fs.readlink() : lee el valor de un enlace simbólico.
  • fs.realpath() : resuelve la ruta de archivo relativa construida con caracteres . y .. en el camino completo.
  • fs.rename() : renombra un archivo o carpeta.
  • fs.rmdir() : elimina la carpeta.
  • fs.stat() : devuelve información del archivo. Métodos similares: fs.fstat() , fs.lstat() .
  • fs.symlink() : crea un nuevo enlace simbólico al archivo.
  • fs.truncate() : trunca el archivo a la longitud especificada. Método similar: fs.ftruncate() .
  • fs.unlink() : elimina un archivo o enlace simbólico.
  • fs.unwatchFile() : deshabilita la supervisión de los cambios de archivos.
  • fs.utimes() : cambia la marca de tiempo de un archivo. Método similar: fs.futimes() .
  • fs.watchFile() : permite monitorear los cambios del archivo. Método similar: fs.watch() .
  • fs.writeFile() : escribe datos en un archivo. Método similar: fs.write() .

Una característica interesante del módulo fs es el hecho de que todos sus métodos, por defecto, son asíncronos, pero también hay versiones sincrónicas de ellos, cuyos nombres se obtienen al agregar la palabra Sync a los nombres de los métodos asincrónicos.

Por ejemplo:

  • fs.rename()
  • fs.renameSync()
  • fs.write()
  • fs.writeSync()

El uso de métodos sincrónicos afecta seriamente el funcionamiento del programa.

Node.js 10 proporciona soporte experimental para estas API basadas en promesas.

Explore el método fs.rename() . Aquí hay una versión asincrónica de este método que utiliza devoluciones de llamada:

 const fs = require('fs') fs.rename('before.json', 'after.json', (err) => { if (err) {   return console.error(err) } // }) 

Cuando se usa su versión síncrona, la construcción try/catch se usa para manejar errores:

 const fs = require('fs') try { fs.renameSync('before.json', 'after.json') // } catch (err) { console.error(err) } 

La principal diferencia entre estas opciones para usar este método es que en el segundo caso, el script se bloqueará hasta que se complete la operación del archivo.

Módulo de ruta


El módulo de ruta, del que también hablamos sobre algunas de sus características, contiene muchas herramientas útiles que le permiten interactuar con el sistema de archivos. Como ya se mencionó, no necesita instalarlo, ya que es parte de Node.js. Para usarlo, es suficiente conectarlo:

 const path = require('path') 

La propiedad path.sep de este módulo proporciona el carácter utilizado para separar segmentos de ruta ( \ en Windows y / en Linux y macOS), y la propiedad path.delimiter proporciona el carácter utilizado para separar múltiples rutas ( ; en Windows y : en Linux y macOS).

Consideremos e ilustremos algunos métodos del módulo de path .

▍path.basename ()


Devuelve el último fragmento de la ruta. Al pasar el segundo parámetro a este método, puede eliminar la extensión del archivo.

 require('path').basename('/test/something') //something require('path').basename('/test/something.txt') //something.txt require('path').basename('/test/something.txt', '.txt') //something 

▍path.dirname ()


Devuelve la parte de la ruta que representa el nombre del directorio:

 require('path').dirname('/test/something') // /test require('path').dirname('/test/something/file.txt') // /test/something 

▍path.extname ()


Devuelve la parte de la ruta que representa la extensión del archivo:

 require('path').extname('/test/something') // '' require('path').extname('/test/something/file.txt') // '.txt' 

▍path.isAbsolute ()


Devuelve verdadero si la ruta es absoluta:

 require('path').isAbsolute('/test/something') // true require('path').isAbsolute('./test/something') // false 

▍path.join ()


Conecta varias partes de la ruta:

 const name = 'flavio' require('path').join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 

▍path.normalize ()


Tratando de descubrir la ruta real basada en la ruta que contiene los caracteres utilizados para construir rutas relativas como . , .. y // :

 require('path').normalize('/users/flavio/..//test.txt') ///users/test.txt 

▍path.parse ()


Convierte una ruta en un objeto cuyas propiedades representan partes individuales de la ruta:

  • root : el directorio raíz.
  • dir : ruta del archivo que comienza desde el directorio raíz
  • base : nombre de archivo y extensión.
  • name : name archivo.
  • ext : extensión de archivo.

Aquí hay un ejemplo usando este método:

 require('path').parse('/users/test.txt') 

Como resultado de su trabajo, se obtiene el siguiente objeto:

 { root: '/', dir: '/users', base: 'test.txt', ext: '.txt', name: 'test' } 

▍path.relative ()


Toma, como argumentos, 2 formas. Devuelve la ruta relativa de la primera a la segunda, según el directorio de trabajo actual:

 require('path').relative('/Users/flavio', '/Users/flavio/test.txt') //'test.txt' require('path').relative('/Users/flavio', '/Users/flavio/something/test.txt') //'something/test.txt' 

▍path.resolve ()


Encuentra la ruta absoluta en función de la ruta relativa que se le pasa:

 path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'      . 

Resumen


Hoy vimos los módulos Node.js fs y path que se utilizan para trabajar con el sistema de archivos. En la siguiente parte de esta serie, en la que termina, discutiremos el sistema os , los events , los módulos http , hablaremos sobre cómo trabajar con flujos y con sistemas de administración de bases de datos en Node.js.

Estimados lectores! ¿Qué paquetes npm utilizas cuando trabajas con el sistema de archivos en Node.js?

Source: https://habr.com/ru/post/es424969/


All Articles