Leer archivos con Node.js

    Una de las cosas m谩s comunes que querr谩 hacer con casi cualquier lenguaje de programaci贸n es abrir y leer un archivo. Con la mayor铆a de los lenguajes, esto es bastante simple, pero para los veteranos de JavaScript puede parecer un poco extra帽o. Durante muchos a帽os, JavaScript solo estuvo disponible en el navegador, por lo que los desarrolladores de aplicaciones para el usuario solo pueden estar familiarizados con el API FileReader o similar.

    Node.js, como probablemente sepa, es muy diferente a su JavaScript t铆pico en el navegador. Tiene su propio conjunto de bibliotecas destinadas a manejar el sistema operativo y las tareas del sistema de archivos, como abrir y leer archivos. En este art铆culo, le mostrar茅 c贸mo usar Node.js para leer archivos. Espec铆ficamente, usaremos el fs m贸dulo para hacer precisamente eso.

    Hay dos formas de abrir y leer un archivo usando el fs m贸dulo:

    • Cargar todo el contenido a la vez (almacenamiento en b煤fer)
    • Cargar contenido de forma incremental (streaming)

    Cada uno de estos m茅todos se explicar谩 en las dos secciones siguientes.

    Almacenamiento en b煤fer de contenido con fs.readFile

    Esta es la forma m谩s com煤n de leer un archivo con Node.js, especialmente para principiantes, debido a su simplicidad y conveniencia. Aunque, como se dar谩 cuenta en la siguiente secci贸n, no es necesariamente el mejor o el m谩s eficiente.

    Aqu铆 hay un ejemplo r谩pido usando fs.readFile:

    var fs = require('fs');
    
    fs.readFile('my-file.txt', 'utf8', function(err, data) {
        if (err) throw err;
        console.log(data);
    });
    

    los data El argumento de la devoluci贸n de llamada contiene el contenido completo del archivo representado como una cadena en utf8 formato. Si omite el utf8 argumento completamente, entonces el m茅todo simplemente devolver谩 el contenido sin procesar en un Buffer objeto. La eliminaci贸n de la utf8 argumento en el c贸digo anterior (y asumiendo que my-file.txt contiene la cadena “隆Hola!”), obtendr铆amos esta salida:

    $ node read-file.js
    <Buffer 48 65 79 20 74 68 65 72 65 21>
    

    Puede que hayas notado que fs.readFile devuelve el contenido en una devoluci贸n de llamada, lo que significa que este m茅todo se ejecuta de forma asincr贸nica. Esto debe usarse siempre que sea posible para evitar bloquear el hilo de ejecuci贸n principal, pero a veces tiene que hacer las cosas de forma sincr贸nica, en cuyo caso Node le proporciona un readFileSync m茅todo.

    Este m茅todo funciona exactamente de la misma manera, excepto que el contenido del archivo se devuelve directamente desde la llamada a la funci贸n y el hilo de ejecuci贸n se bloquea mientras carga el archivo. Normalmente uso esto en las secciones de inicio de mis programas (como cuando estamos cargando archivos de configuraci贸n) o en aplicaciones de l铆nea de comandos donde bloquear el hilo principal no es un gran problema.

    A continuaci贸n, se explica c贸mo cargar un archivo sincr贸nicamente con Node:

    var fs = require('fs');
    
    try {
        var data = fs.readFileSync('my-file.txt', 'utf8');
        console.log(data);    
    } catch(e) {
        console.log('Error:', e.stack);
    }
    

    Observe que con la llamada de bloqueo (sincr贸nica) tenemos que usar try...catch para manejar cualquier error, a diferencia de la versi贸n sin bloqueo (asincr贸nica) donde los errores simplemente se nos pasan como argumentos.

    Aparte de la forma en que estos m茅todos devuelven datos y manejan errores, funcionan de la misma manera.

    Transmisi贸n de contenido con fs.createReadStream

    La segunda forma de abrir y leer un archivo es abrirlo como Corriente utilizando el fs.createReadStream m茅todo. Todos los flujos de node son instancias del EventEmitter objeto, lo que le permite suscribirse a eventos importantes.

    Un objeto de flujo legible puede ser 煤til por muchas razones, algunas de las cuales incluyen:

    • Huella de memoria m谩s peque帽a. Dado que los datos del archivo de destino se cargan en trozos, no se requiere tanta memoria para almacenar los datos en un b煤fer.
    • Tiempo de respuesta m谩s r谩pido. Para aplicaciones urgentes, el tiempo entre la solicitud y la respuesta es cr铆tico. Las transmisiones reducen el tiempo de respuesta (especialmente para archivos grandes) ya que no necesitan esperar para cargar todo el archivo antes de devolver los datos.
    • Datos de tuber铆as. La abstracci贸n de flujo le permite utilizar una interfaz com煤n entre productores y consumidores de datos para pasar esos datos a trav茅s de conductos. Esto es muy similar al Tuber铆a Unix concepto.

    Aunque realmente no es muy dif铆cil usar las transmisiones, pueden ser un poco intimidantes y no son tan intuitivas como las fs.readFile m茅todo. Aqu铆 est谩 el ‘hola mundo’ de la transmisi贸n de archivos:

    var fs = require('fs');
    
    var data="";
    
    var readStream = fs.createReadStream('my-file.txt', 'utf8');
    
    readStream.on('data', function(chunk) {
        data += chunk;
    }).on('end', function() {
        console.log(data);
    });
    

    Este c贸digo hace exactamente lo que hace el c贸digo de la primera secci贸n, excepto que tenemos que “recopilar” fragmentos de datos antes de imprimirlos en la consola. Si su archivo es bastante peque帽o, probablemente solo reciba un solo fragmento, pero para archivos m谩s grandes, como audio y video, tendr谩 que recopilar varios fragmentos. Este es el caso en el que comenzar谩 a notar el valor real de la transmisi贸n de archivos.

    Tenga en cuenta que el ejemplo que mostr茅 anteriormente frustra en su mayor铆a el prop贸sito de usar un flujo, ya que terminamos recopilando los datos en un b煤fer (variable) de todos modos, pero al menos le da una idea de c贸mo funcionan. Un mejor ejemplo que muestra las fortalezas de los flujos de archivos se puede ver aqu铆, en una ruta Express que maneja una solicitud de archivo:

    var fs = require('fs');
    var path = require('path');
    var http = require('http');
    
    var staticBasePath="./static";
    
    var staticServe = function(req, res) {
        var fileLoc = path.resolve(staticBasePath);
        fileLoc = path.join(fileLoc, req.url);
        
            var stream = fs.createReadStream(fileLoc);
    
            stream.on('error', function(error) {
                res.writeHead(404, 'Not Found');
                res.end();
            });
    
            stream.pipe(res);
    };
    
    var httpServer = http.createServer(staticServe);
    httpServer.listen(8080);
    

    Todo lo que hacemos aqu铆 es abrir el archivo con fs.createReadStream y canalizarlo al objeto de respuesta, res. Incluso podemos suscribirnos a error eventos y manejarlos a medida que ocurren. Es un m茅todo mucho mejor para manejar archivos una vez que aprenda a usarlo correctamente. Para obtener un ejemplo y una explicaci贸n m谩s completos del c贸digo anterior, consulte este art铆culo sobre la creaci贸n de servidores de archivos est谩ticos con Node.

    Conclusi贸n

    En este art铆culo, deber铆a haber aprendido los conceptos b谩sicos de la lectura de archivos, as铆 como algunos m茅todos de carga avanzados con objetos Stream. Saber cu谩ndo usarlos es la clave y se debe considerar cuidadosamente para aplicaciones con restricciones de memoria o de tiempo.

    驴Cu谩l es su m茅todo preferido para manejar archivos? 驴C贸mo ha utilizado Streams en el pasado? 隆H谩znoslo saber en los comentarios!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *