Obtener datos de fs.readFile

296
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Registros undefined, ¿por qué?

karaxuna
fuente
1
fs.readFileSync también tiene características interesantes para leer un archivo incluso si está en el formato utico8 unicode.
Praneeth
NB fs.readFile también puede hacer eso ^ vea mi respuesta a continuación
Dominic

Respuestas:

348

Para explicar en detalle lo que dijo @Raynos, la función que ha definido es una devolución de llamada asincrónica. No se ejecuta de inmediato, sino que se ejecuta cuando se completa la carga del archivo. Cuando llama a readFile, el control se devuelve inmediatamente y se ejecuta la siguiente línea de código. Entonces, cuando llama a console.log, su devolución de llamada aún no se ha invocado y este contenido aún no se ha configurado. Bienvenido a la programación asincrónica.

Enfoques de ejemplo

const fs = require('fs');
// First I want to read the file
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    const content = data;

    // Invoke the next step here however you like
    console.log(content);   // Put all of the code here (not the best solution)
    processFile(content);   // Or put the next step in a function and invoke it
});

function processFile(content) {
    console.log(content);
}

O mejor aún, como muestra el ejemplo de Raynos, envuelva su llamada en una función y pase sus propias devoluciones de llamada. (Aparentemente, esta es una mejor práctica) Creo que adquirir el hábito de envolver sus llamadas asíncronas en una función que tome una devolución de llamada le ahorrará muchos problemas y códigos desordenados.

function doSomething (callback) {
    // any async callback invokes callback with response
}

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});
Matt Esch
fuente
2
Sync I / O tiene su lugar: está bien si está haciendo una pequeña herramienta o sistema de compilación. En sistemas más grandes o aplicaciones de servidor, la mejor práctica es evitarlo.
RobW
28
No todo es un servidor web. Y no hay nada de horrible en usar versiones sincronizadas de métodos para llamadas de una sola vez antes de que el servidor haya comenzado a recibir solicitudes. Cualquiera que use Node realmente debería entender por qué antes de usarlo. Definitivamente antes de despotricar sobre esto.
Erik Reppen
77
Debe incluir 'utf8'después del nombre de archivo como parámetro adicional, de lo contrario, solo devolverá un búfer. Ver: stackoverflow.com/questions/9168737/…
DollarAkshay
252

En realidad, hay una función síncrona para esto:

http://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_encoding

Asincrónico

fs.readFile(filename, [encoding], [callback])

Lee asincrónicamente todo el contenido de un archivo. Ejemplo:

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

La devolución de llamada pasa dos argumentos (err, data), donde data es el contenido del archivo.

Si no se especifica codificación, se devuelve el búfer sin procesar.


SINCRÓNICO

fs.readFileSync(filename, [encoding])

Versión sincrónica de fs.readFile. Devuelve el contenido del archivo llamado nombre de archivo.

Si se especifica la codificación, esta función devuelve una cadena. De lo contrario, devuelve un búfer.

var text = fs.readFileSync('test.md','utf8')
console.log (text)
Logan
fuente
Pregunta rápida, ¿para qué sirve el búfer que se devuelve en la versión síncrona de readFile? Si leo un archivo sincrónicamente y no paso ninguna codificación, imprime el búfer, ¿cómo puedo usar esto? Gracias.
codingbbq
12
Tuve experiencia con esto recientemente. Digamos que nuestro buffer es data. if (Buffer.isBuffer( data){ result = data.toString('utf8'); }Ahora hemos convertido el búfer en texto legible. Esto es bueno para leer un archivo de texto sin formato o probar el archivo con los tipos de formato. Podría hacer un try / catch para ver si es un archivo JSON, por ejemplo; pero solo después de que el búfer se convierta en texto. Mire aquí para obtener más información: nodejs.org/api/buffer.html
Logan
Además, que yo sepa, los buffers son flujos de octetos, y son buenos para enviar datos "pieza por pieza". Debes haber visto que el búfer es algo así AF 42 F1. Muy práctico para la comunicación cliente-servidor-cliente.
Logan
113
function readContent(callback) {
    fs.readFile("./Index.html", function (err, content) {
        if (err) return callback(err)
        callback(null, content)
    })
}

readContent(function (err, content) {
    console.log(content)
})
Raynos
fuente
66
muchas gracias, si tuviera 15 puntos, votaría su respuesta :)
karaxuna
Hola, en la primera línea de tu código function readContent(callback), ¿es callbackuna palabra reservada? Quiero decir, ¿es esta la forma estándar de implementar devoluciones de llamada para sus funciones personalizadas? Acabo de empezar a aprender nodo.
Amal Antony
3
Hola amal La devolución de llamada es simplemente el argumento pasado a su función, podría ser evento ccualquier nombre que desee, no es una palabra reservada en Javascript, y supongo que lo mismo se extiende a Node.js.
RealDeal_EE'18
readContent(function (err, content)me da un error de sintaxis al usar la función como parámetro.
Monsto
66

Usando promesas con ES7

Uso asincrónico con mz / fs

El mzmódulo proporciona versiones prometidas de la biblioteca del nodo central. Usarlos es simple. Primero instale la biblioteca ...

npm install mz

Luego...

const fs = require('mz/fs');
fs.readFile('./Index.html').then(contents => console.log(contents))
  .catch(err => console.error(err));

Alternativamente, puede escribirlos en funciones asincrónicas:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};
Evan Carroll
fuente
66
este es el futuro y debería ser altamente votado por todos :) gracias
PirateApp
2
parece interesante. Un error tipográfico: 'console.error (catch)' debería ser 'console.error (err)' supongo).
philwalk
2
Si no desea agregar un paquete adicional, pruebe la solución de
@doctorlee a
18
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

use esto para llamar a un archivo sincrónicamente, sin codificar su salida de muestra como un búfer.

usuario2266928
fuente
2
Se necesita una línea en blanco antes de los bloques de código para que la impresión bastante en arrancar.
royhowie
informado y lo mejor!
Diamante
13

Esta línea funcionará

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);
Aravin
fuente
1
Pasaron 7 años :) fs.readFileSynces un método de sincronización, por lo que no es necesario await. Aguardar es útil con promesas ( nodejs.org/api/fs.html#fs_fs_promises_api ), cuando desea escribir código asíncrono con una sintaxis similar al código de sincronización.
karaxuna
@karaxuna, sí. remoto. Acabo de encontrarme con este caso hoy y resolví usando el código anterior.
Aravin el
1
Esta es la respuesta más simple. Si no necesita asíncrono, ¿por qué en el mundo se mezclaría con la versión asíncrona, con devoluciones de llamada, asíncrono / espera, etc.? Este es el camino a seguir.
Maestro de patos
8
const fs = require('fs')
function readDemo1(file1) {
    return new Promise(function (resolve, reject) {
        fs.readFile(file1, 'utf8', function (err, dataDemo1) {
            if (err)
                reject(err);
            else
                resolve(dataDemo1);
        });
    });
}
async function copyFile() {

    try {
        let dataDemo1 = await readDemo1('url')
        dataDemo1 += '\n' +  await readDemo1('url')

        await writeDemo2(dataDemo1)
        console.log(dataDemo1)
    } catch (error) {
        console.error(error);
    }
}
copyFile();

function writeDemo2(dataDemo1) {
    return new Promise(function(resolve, reject) {
      fs.writeFile('text.txt', dataDemo1, 'utf8', function(err) {
        if (err)
          reject(err);
        else
          resolve("Promise Success!");
      });
    });
  }
doctorlee
fuente
55
Por favor, no solo ponga código en su respuesta ... explique por qué es diferente y cómo resuelve el problema.
Studocwho
@doctorlee Esto realmente funciona para mí, sin ninguna biblioteca externa. Se requiere una explicación segura.
Ashutosh Chamoli
7

sincronización y lectura de archivos asíncronos:

//fs module to read file in sync and async way

var fs = require('fs'),
    filePath = './sample_files/sample_css.css';

// this for async way
/*fs.readFile(filePath, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
});*/

//this is sync way
var css = fs.readFileSync(filePath, 'utf8');
console.log(css);

Node Cheat Disponible en read_file .

Zeeshan Hassan Memon
fuente
7

Como se dijo, fs.readFilees una acción asincrónica. Significa que cuando le dice al nodo que lea un archivo, debe tener en cuenta que tomará algún tiempo y, mientras tanto, el nodo continuó ejecutando el siguiente código. En tu caso es:console.log(content); .

Es como enviar una parte de su código para un viaje largo (como leer un archivo grande).

Echa un vistazo a los comentarios que he escrito:

var content;

// node, go fetch this file. when you come back, please run this "read" callback function
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});

// in the meantime, please continue and run this console.log
console.log(content);

Es por eso contentque todavía está vacío cuando lo registras. El nodo aún no ha recuperado el contenido del archivo.

Esto podría resolverse moviéndose console.log(content)dentro de la función de devolución de llamada, justo después content = data;. De esta manera, verá el registro cuando el nodo termine de leer el archivo y luego contentobtenga un valor.

Taitu-lism
fuente
6

Use la biblioteca de promisify incorporada (Nodo 8+) para hacer que estas antiguas funciones de devolución de llamada sean más elegantes.

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

async function doStuff() {
  try {
    const content = await readFile(filePath, 'utf8');
    console.log(content);
  } catch (e) {
    console.error(e);
  }
}
Dominic
fuente
Puede estar en una sola línea const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');, sin necesidad de util.promisify wrap.
rab
1
El objetivo de esto es no usar la versión de sincronización, y debe manejar los errores al llamarla
Dominic
4
var fs = require('fs');
var path = (process.cwd()+"\\text.txt");

fs.readFile(path , function(err,data)
{
    if(err)
        console.log(err)
    else
        console.log(data.toString());
});
Masoud Siahkali
fuente
2
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Esto es solo porque el nodo es asíncrono y no esperará la función de lectura y tan pronto como el programa se inicie, consolará el valor como indefinido, lo cual es realmente cierto porque no hay un valor asignado a la variable de contenido. Para manejar podemos usar promesas, generadores, etc. Podemos usar promesas de esta manera.

new Promise((resolve,reject)=>{
    fs.readFile('./index.html','utf-8',(err, data)=>{
        if (err) {
            reject(err); // in the case of error, control flow goes to the catch block with the error occured.
        }
        else{
            resolve(data);  // in the case of success, control flow goes to the then block with the content of the file.
        }
    });
})
.then((data)=>{
    console.log(data); // use your content of the file here (in this then).    
})
.catch((err)=>{
    throw err; //  handle error here.
})
Nouman Dilshad
fuente
2

La siguiente función funcionaría para asyncencapsular o thencadenas de promesa

const readFileAsync =  async (path) => fs.readFileSync(path, 'utf8');
rab
fuente
1

puedes leer el archivo por

var readMyFile = function(path, cb) {
      fs.readFile(path, 'utf8', function(err, content) {
        if (err) return cb(err, null);
        cb(null, content);
      });
    };

Agregando puede escribir en el archivo,

var createMyFile = (path, data, cb) => {
  fs.writeFile(path, data, function(err) {
    if (err) return console.error(err);
    cb();
  });
};

e incluso encadenarlo

var readFileAndConvertToSentence = function(path, callback) {
  readMyFile(path, function(err, content) {
    if (err) {
      callback(err, null);
    } else {
      var sentence = content.split('\n').join(' ');
      callback(null, sentence);
    }
  });
};
J. Doe
fuente
1

Para decirlo más o menos, se trata de node.js, que es de naturaleza asíncrona.

Cuando hablamos de asíncrono, estamos hablando de hacer o procesar información o datos mientras tratamos con otra cosa. No es sinónimo de paralelo, recuerde.

Tu codigo:

var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Con su muestra, básicamente hace primero la parte de console.log, por lo tanto, la variable 'contenido' no está definida.

Si realmente quieres la salida, haz algo como esto en su lugar:

var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
    console.log(content);
});

Esto es asincrónico. Será difícil acostumbrarse, pero es lo que es. Nuevamente, esta es una explicación aproximada pero rápida de lo que es asíncrono.

DayIsGreen
fuente