Obter dados de fs.readFile

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

Logs undefined, por quê?

karaxuna
fonte
1
O fs.readFileSync também possui recursos interessantes para ler um arquivo, mesmo que esteja no formato utf8 unicode.
Praneeth
NB fs.readFile também pode fazer isso ^ veja minha resposta abaixo
Dominic

Respostas:

348

Para elaborar o que o @Raynos disse, a função que você definiu é um retorno de chamada assíncrono. Ele não é executado imediatamente, é executado quando o carregamento do arquivo é concluído. Quando você chama readFile, o controle é retornado imediatamente e a próxima linha de código é executada. Portanto, quando você chama console.log, seu retorno de chamada ainda não foi invocado e esse conteúdo ainda não foi definido. Bem-vindo à programação assíncrona.

Abordagens de exemplo

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);
}

Ou melhor ainda, como mostra o exemplo do Raynos, envolva sua chamada em uma função e transmita seus próprios retornos de chamada. (Aparentemente, essa é uma prática recomendada). Acho que adquirir o hábito de agrupar suas chamadas assíncronas na função que recebe um retorno de chamada economizará muitos problemas e códigos confusos.

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

doSomething (function doSomethingAfter(err, result) {
    // process the async result
});
Matt Esch
fonte
2
A E / S de sincronização tem seu lugar - tudo bem se você estiver executando um pequeno sistema ou ferramenta de construção. Em sistemas maiores ou aplicativos de servidor, a melhor prática é evitá-lo.
RobW
27
Nem tudo é um servidor web. E não há nada de horrível em usar versões de sincronização de métodos para chamadas únicas antes que o servidor comece a receber solicitações. Qualquer pessoa que use o Node deve realmente entender o porquê antes de usá-lo. Definitivamente antes de discutir sobre isso.
Erik Reppen
7
Você deve incluir 'utf8'o nome do arquivo como parâmetro adicional, caso contrário, ele retornará um buffer. Veja: stackoverflow.com/questions/9168737/…
DollarAkshay 12/02/19
252

Na verdade, existe uma função síncrona para isso:

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

Assíncrono

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

Lê assincronamente todo o conteúdo de um arquivo. Exemplo:

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

O retorno de chamada recebe dois argumentos (err, data), em que data é o conteúdo do arquivo.

Se nenhuma codificação for especificada, o buffer bruto será retornado.


SÍNCRONO

fs.readFileSync(filename, [encoding])

Versão síncrona do fs.readFile. Retorna o conteúdo do arquivo chamado filename.

Se a codificação for especificada, essa função retornará uma sequência. Caso contrário, ele retornará um buffer.

var text = fs.readFileSync('test.md','utf8')
console.log (text)
Logan
fonte
Pergunta rápida, qual é o uso do buffer que está sendo retornado na versão síncrona do readFile? Se eu ler um arquivo de forma síncrona e não passar nenhuma codificação, ele imprimirá o buffer, como posso usar isso? Obrigado.
Codingbbq
12
Eu tive experiência com isso recentemente. Digamos que nosso buffer seja data. if (Buffer.isBuffer( data){ result = data.toString('utf8'); }Agora nós convertemos o buffer em texto legível. Isso é bom para ler um arquivo de texto sem formatação ou testar o arquivo em relação aos tipos de formato. Eu poderia tentar / capturar para ver se é um arquivo JSON, por exemplo; mas somente após o buffer ser convertido em texto. Procure aqui para obter mais informações: nodejs.org/api/buffer.html
Logan
Também, até onde eu sei, os buffers são fluxos de octetos e são bons para enviar dados "peça por peça". Você deve ter visto que o buffer é algo parecido AF 42 F1. Muito prático para comunicação 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
fonte
6
muito obrigado, se eu tivesse 15 marcas, eu iria votar a sua resposta :)
karaxuna
Olá, na primeira linha do seu código function readContent(callback), é callbackuma palavra reservada? Quero dizer, essa é a maneira padrão de implementar retornos de chamada para suas funções personalizadas? Eu apenas comecei a aprender o nó.
Amal Antony
3
Oi Amal. O retorno de chamada é simplesmente o argumento passado para sua função, poderia ser eventou cqualquer nome que você quiser - não é uma palavra reservada em Javascript, e eu assumiria que o mesmo se estende ao Node.js.
RealDeal_EE'18
readContent(function (err, content)me dá um erro de sintaxe ao usar a função como parâmetro.
monsto
66

Usando promessas com o ES7

Uso assíncrono com mz / fs

O mzmódulo fornece versões promissificadas da biblioteca de nós principais. Usá-los é simples. Primeiro instale a biblioteca ...

npm install mz

Então...

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

Como alternativa, você pode escrevê-los em funções assíncronas:

async function myReadfile () {
  try {
    const file = await fs.readFile('./Index.html');
  }
  catch (err) { console.error( err ) }
};
Evan Carroll
fonte
6
este é o futuro e deve ser altamente votado por todos :) obrigado
PirateApp 13/08/16
2
parece interessante. Um erro de digitação: 'console.erro (captura)' deve ser 'console.erro (erro)' eu presumo).
27617 phil philwalk
2
Se você não quiser adicionar um pacote extra, tente @doctorlee 's solução abaixo
rahuljain1311
18
var data = fs.readFileSync('tmp/reltioconfig.json','utf8');

use isso para chamar um arquivo de forma síncrona, sem codificar sua saída de exibição como um buffer.

user2266928
fonte
2
Você precisa de uma linha em branco antes de blocos de código para que a impressão de muito para chutar.
royhowie
informado e o melhor!
Diamond
13

Esta linha irá funcionar,

const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);
Aravin
fonte
1
7 anos se passaram :) fs.readFileSyncé o método de sincronização, então não há necessidade awaitdisso. Aguardar é útil com promessas ( nodejs.org/api/fs.html#fs_fs_promises_api ), quando você deseja escrever código assíncrono com sintaxe semelhante ao código de sincronização.
karaxuna
@karaxuna, sim. removido. Acabei de encontrar este caso hoje e resolvi usar o código acima.
Aravin
1
Essa é a resposta mais simples. Se você não precisa de assíncrono, por que diabos você misturaria com a versão assíncrona, com retornos de chamada, assíncrono / espera, etc ?. Este é o caminho a percorrer.
Master of Ducks
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
fonte
5
Por favor, não coloque apenas o código na sua resposta ... explique por que é diferente e como resolve o problema.
precisa saber é o seguinte
@doctorlee Isso realmente funciona para mim, sem nenhuma biblioteca externa. A explicação é necessária, com certeza.
Ashutosh Chamoli
7

maneira de ler arquivos sincronizados e assí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);

Fraude do nó Disponível em read_file .

Zeeshan Hassan Memon
fonte
7

Como dito, fs.readFileé uma ação assíncrona. Isso significa que, quando você instrui o nó a ler um arquivo, é necessário considerar que levará algum tempo e, enquanto isso, o nó continuará executando o código a seguir. No seu caso, é:console.log(content); .

É como enviar parte do seu código para uma longa viagem (como ler um arquivo grande).

Dê uma olhada nos comentários que escrevi:

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);

É por isso content ainda está vazio quando você o registra. O nó ainda não recuperou o conteúdo do arquivo.

Isso pode ser resolvido movendo-se para console.log(content)dentro da função de retorno de chamada, logo após content = data;. Dessa forma, você verá o log quando o nó terminar de ler o arquivo e depois contentobtém um valor.

Taitu-lism
fonte
6

Use a biblioteca promisify incorporada (Nó 8+) para tornar essas funções antigas de retorno de chamada mais 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
fonte
Pode estar em linha única const doStuff = async (filePath) => fs.readFileSync(filePath, 'utf8');, sem necessidade de quebra de util.promisify.
rab
1
Não usando a versão de sincronização é o ponto deste, e você deve lidar com erros em chamá-lo
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
fonte
2
var content;
fs.readFile('./Index.html', function read(err, data) {
    if (err) {
        throw err;
    }
    content = data;
});
console.log(content);

Isso ocorre apenas porque o nó é assíncrono e não espera a função de leitura. Assim que o programa for iniciado, o valor do console será definido como indefinido, o que é realmente verdadeiro porque não há valor atribuído à variável de conteúdo. Para lidar, podemos usar promessas, geradores, etc. Podemos usar a promessa dessa maneira.

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
fonte
2

O seguinte é função funcionaria para asyncencapsular ou prometer thencadeias

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

você pode ler o arquivo

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

Adicionando você pode gravar em um arquivo,

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

e até encadeá-lo

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
fonte
1

Em outras palavras, você está lidando com o node.js, que é de natureza assíncrona.

Quando falamos de assíncrono, estamos falando sobre fazer ou processar informações ou dados enquanto lida com outra coisa. Não é sinônimo de paralelo, lembre-se.

Seu código:

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

Com sua amostra, ele basicamente faz a parte console.log primeiro, portanto a variável 'conteúdo' é indefinida.

Se você realmente deseja a saída, faça algo assim:

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

Isso é assíncrono. Vai ser difícil se acostumar, mas é o que é. Novamente, esta é uma explicação grosseira, mas rápida, do que é assíncrono.

DayIsGreen
fonte