Escribir en archivos en Node.js

Escribir en archivos es una necesidad frecuente cuando se programa en cualquier lenguaje. Al igual que otros lenguajes de programación, JavaScript con Node.js facilita el manejo del sistema de archivos...

Introducción

Escribir en archivos es una necesidad frecuente cuando se programa en cualquier lenguaje. Al igual que otros lenguajes de programación, JavaScript con Node.js hace que el manejo del sistema de archivos sea intuitivo mediante el uso de un módulo que se ocupa del sistema de archivos del sistema operativo.

El módulo fs contiene la funcionalidad para manipular archivos y tratar con el sistema de archivos de la plataforma informática. Además de leer y escribir en archivos, puede usar el módulo para consultar estadísticas de archivos, como tamaños y recuentos de archivos.

Por defecto, el módulo fs escribirá archivos con una codificación de 'utf8'. UTF-8 es una codificación comúnmente utilizada en páginas web y otros documentos. La codificación de archivos se refiere al conjunto de caracteres que se utiliza para el contenido del archivo. Las codificaciones comúnmente utilizadas son 'utf8', 'ascii', 'binary', 'hex', 'base64' y 'utf16le'.

Cada codificación de caracteres tiene ventajas específicas e instancias en las que tiene más sentido. Por ejemplo, 'ascii' es una codificación fácil de leer y escribir, pero eliminará el bit alto del flujo de datos. Por razones como esta, querrá seleccionar la codificación de caracteres con cuidado.

En las próximas secciones, presentaremos las diferentes formas en que fs le permite escribir en el sistema de archivos, incluidas sus diferencias y ventajas.

Método 1: usar fs.writeFile

El módulo fs incluye un método writeFile de alto nivel que puede escribir datos en archivos de forma asíncrona. Esto significa que, al igual que con muchas operaciones en Node.js, la E/S no bloquea y emite un evento cuando finaliza la operación. Podemos escribir una función de devolución de llamada para que se ejecute cuando ‘writeFile’ regrese.

Aquí hay un ejemplo de código simple de escribir algunas letras de canciones en un archivo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// writefile.js

const fs = require('fs');

let lyrics = 'But still I\'m having memories of high speeds when the cops crashed\n' + 
             'As I laugh, pushin the gas while my Glocks blast\n' + 
             'We was young and we was dumb but we had heart';

// write to a new file named 2pac.txt
fs.writeFile('2pac.txt', lyrics, (err) => {
    // throws an error, you could also catch it here
    if (err) throw err;

    // success case, the file was saved
    console.log('Lyric saved!');
});

Especificamos el nombre del archivo, junto con los caracteres para escribir, así como una función de devolución de llamada para ejecutar cuando el método regrese. También podemos pasar un objeto de opciones o una cadena que especifique la codificación a usar, así como el modo y la bandera. Si necesita especificar la codificación de caracteres, esta es la forma en que deberá llamar al método:

1
fs.writeFile('2pac.txt', 'Some other lyric', 'ascii', callback);

Tenga en cuenta que si el archivo aún no existe, llamar a este método también creará el archivo, por lo que no necesita preocuparse por eso.

Hay un método síncrono fs.writeFileSync que puede usar en lugar de fs.writeFile.

La diferencia es que el método fs.writeFileSync realiza operaciones de entrada/salida sincrónicamente, bloqueando el bucle de eventos de Node.js mientras se escribe el archivo. Esto puede interferir con el rendimiento de su aplicación Node.js si se excede con estas escrituras sincrónicas. En la mayoría de los casos, debería preferir usar las escrituras asíncronas.

Solo sepa que debe tener cuidado al usar estos dos métodos porque crearán un nuevo archivo cada vez o reemplazarán el contenido si ya existe. Si simplemente desea actualizar un archivo existente, querrá usar appendFile, que veremos más adelante en este artículo.

Método 2: usar fs.write

A diferencia de los métodos fs.writeFile y fs.writeFileSync de alto nivel, puede aprovechar un mayor control al escribir en archivos en Node.js utilizando el método fs.write de bajo nivel. El método fs.write permite un control preciso sobre la posición en el archivo para comenzar a escribir, un búfer que puede especificar para escribir, así como qué parte del búfer desea escribir en el archivo.

Además, el uso de la funcionalidad de escritura de bajo nivel le permite saber con precisión cuándo se publican los descriptores de archivos y responder en consecuencia, por ejemplo, mediante el envío de notificaciones automáticas en su aplicación.

Aquí hay un ejemplo en el que escribimos otras pocas líneas de letras en un archivo diferente usando fs.write.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// fs_write.js

const fs = require('fs');

// specify the path to the file, and create a buffer with characters we want to write
let path = 'ghetto_gospel.txt';
let buffer = new Buffer('Those who wish to follow me\nI welcome with my hands\nAnd the red sun sinks at last');

// open the file in writing mode, adding a callback function where we do the actual writing
fs.open(path, 'w', function(err, fd) {
    if (err) {
        throw 'could not open file: ' + err;
    }

    // write the contents of the buffer, from position 0 to the end, to the file descriptor returned in opening our file
    fs.write(fd, buffer, 0, buffer.length, null, function(err) {
        if (err) throw 'error writing file: ' + err;
        fs.close(fd, function() {
            console.log('wrote the file successfully');
        });
    });
});

Querrá usar fs.write cuando realice actualizaciones detalladas de archivos, por ejemplo, escribiendo una secuencia de bytes en una posición conocida en medio de un archivo.

Estos métodos funcionan con descriptores de archivos, y debe abrir el archivo para escribir con fs.open y luego, al final, cerrarlo nuevamente con fs.close para evitar pérdidas de memoria.

Método 3: usar fs.createWriteStream

Cuando se manejan archivos particularmente grandes, o archivos que vienen en fragmentos, digamos desde una conexión de red, es preferible usar arroyos que escribir archivos de una sola vez a través de los métodos anteriores. que escriben archivos completos.

Los flujos escriben pequeñas cantidades de datos a la vez. Si bien esto tiene la desventaja de ser más lento porque los datos se transfieren en fragmentos, tiene ventajas para el rendimiento de la RAM. Dado que el archivo completo no se carga en la memoria de una sola vez, el uso de RAM es menor.

Para escribir en un archivo usando secuencias, debe crear una nueva secuencia grabable. Luego puede escribir datos en el flujo a intervalos, todos a la vez, o de acuerdo con la disponibilidad de datos de un servidor u otro proceso, luego cerrar el flujo definitivamente una vez que se hayan escrito todos los paquetes de datos.

Aquí hay un ejemplo de código de cómo hacemos esto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// write_stream.js

const fs = require('fs');

let writeStream = fs.createWriteStream('secret.txt');

// write some data with a base64 encoding
writeStream.write('aef35ghhjdk74hja83ksnfjk888sfsf', 'base64');

// the finish event is emitted when all data has been flushed from the stream
writeStream.on('finish', () => {
    console.log('wrote all data to file');
});

// close the stream
writeStream.end();

Creamos un flujo de escritura y luego escribimos algunos datos en el flujo. Hemos incluido una declaración de registro cuando se emite el evento "finalizar", que nos permite saber que todos los datos se han vaciado al sistema subyacente. En este caso, eso significa que todos los datos se han escrito en el sistema de archivos.

Dadas las ventajas de rendimiento, las secuencias son una técnica que verá que se usa ampliamente en el territorio de Node.js, no solo para escribir archivos. Otro ejemplo sería usar flujos para recibir datos de una conexión de red.

Gestión de errores al escribir en un archivo {#gestión de errores al escribir en un archivo}

Al escribir en archivos, pueden ocurrir muchos errores diferentes durante la entrada/salida. Su código debe abordar estos posibles errores. Una cosa simple que puede hacer es arrojar los errores como excepciones de Node.js. Esto bloquea el programa y, por lo tanto, no se recomienda, excepto en los casos en los que tiene pocos recursos.

Por ejemplo, si el error solo puede ocurrir como un error del programador, también conocido como error, entonces bloquear el programa puede ser la mejor respuesta, ya que alerta al programador del error de inmediato y no oculta el error.

Cuando se trata de errores operativos, como especificar una ruta que es inaccesible, hay dos enfoques a seguir. Una es llamar a una función de devolución de llamada con el error. En la devolución de llamada, incluye alguna lógica para manejar el error, como registrarlo.

Alternativamente, puede incluir bloques try/catch alrededor del código llamando a la sección del programa donde pueden ocurrir errores.

Agregar a un archivo con fs.appendFile {#agregar a un archivo con fsappendfile}

En los casos en los que solo queremos agregar al contenido de un archivo, podemos usar el método de alto nivel fs.appendFile y su contraparte síncrona, fs.appendFileSync. El uso de fs.appendFile crea el archivo si no existe y lo agrega al archivo de lo contrario.

Aquí hay un ejemplo del uso de fs.appendFile para escribir en un archivo.

1
2
3
4
5
6
7
8
9
// append_file.js

const fs = require('fs');

// add a line to a lyric file, using appendFile
fs.appendFile('empirestate.txt', '\nRight there up on Broadway', (err) => {
    if (err) throw err;
    console.log('The lyrics were updated!');
});

Aquí, estamos usando appendFile para agregar una línea adicional a un archivo que contiene las siguientes letras:

1
2
3
4
5
6
// empirestate.txt

Empire State of Mind - JAY-Z

I used to cop in Harlem;
hola, my Dominicanos

El uso de fs.appendFile no sobrescribe el archivo, sino que lo actualiza desde la posición final, con los nuevos datos que agregamos. Esta es una función útil cuando solo desea actualizar un archivo, como agregar datos continuamente a un solo archivo de registro.

Entonces, después de ejecutar nuestro código, el archivo de texto se verá así:

1
2
3
4
5
6
7
// empirestate.txt

Empire State of Mind - JAY-Z

I used to cop in Harlem;
hola, my Dominicanos
Right there up on Broadway

Como puede ver, el texto anterior todavía está allí y nuestra nueva cadena se ha agregado al final.

Más información {#más información}

¿Quiere aprender más sobre los fundamentos de Node.js? Personalmente, recomendaría tomar un curso en línea como Aprenda Node.js por Wes Bos. No solo aprenderá la sintaxis ES2017 más actualizada, sino que podrá crear una aplicación de restaurante de pila completa. Según mi experiencia, crear aplicaciones del mundo real como esta es la forma más rápida de aprender.

Conclusión

Como vimos, existen múltiples enfoques a considerar al escribir en un archivo en Node.js. La forma más sencilla, ya menudo la más apropiada, es usar el método writeFile en el módulo fs. Esto le permite escribir en una ruta de archivo específica, con un comportamiento asíncrono, y crea un nuevo archivo o reemplaza uno si existe en la ruta.

Si está escribiendo archivos más grandes, debe considerar las capacidades de escritura fragmentada de los flujos de escritura. Estos permiten escribir búferes de datos en fragmentos, en lugar de cargar todos los datos a la vez en la memoria. El uso de transmisiones lo ayuda a lograr un mejor rendimiento en tales casos.

Para situaciones especiales, puede usar las utilidades fs de nivel inferior como fs.write. El módulo fs admite operaciones de escritura de archivos de grano fino para satisfacer sus necesidades específicas.