Usando o Node.JS, como leio um arquivo JSON na memória (servidor)?

618

fundo

Estou fazendo algumas experiências com o Node.js e gostaria de ler um objeto JSON, de um arquivo de texto ou de um arquivo .js (o que é melhor?) Na memória para que eu possa acessar esse objeto rapidamente a partir do código. Eu percebo que existem coisas como Mongo, Alfred, etc, por aí, mas não é isso que eu preciso agora.

Questão

Como leio um objeto JSON de um arquivo de texto ou js e na memória do servidor usando JavaScript / Node?

Matt Cashatt
fonte
1
como você chama a memória do servidor? seu script nodejs funcionará enquanto você o fizer, mas você precisará armazenar dados em algum lugar, a menos que você torne o script nodejs persistente.
Mpm #

Respostas:

1205

Sincronizar:

var fs = require('fs');
var obj = JSON.parse(fs.readFileSync('file', 'utf8'));

Assíncrono:

var fs = require('fs');
var obj;
fs.readFile('file', 'utf8', function (err, data) {
  if (err) throw err;
  obj = JSON.parse(data);
});
mihai
fonte
15
Eu acho que o JSON.parse é síncrono, é diretamente da v8, o que significa que mesmo com a maneira assíncrona, as pessoas precisam ter cuidado com os grandes arquivos JSON. pois amarraria o nó.
Sean_A91
25
Por uma questão de completude. Existe um npm chamado jsonfile .
Stefan
5
Não acredito que foi tão difícil encontrar essa coisa simples. Cada resposta que recebi do Google estava fazendo um HTTPRequest ou usando JQuery ou fazê-lo no navegador
juliangonzalez
6
dois pontos: (1) A resposta síncrona deve ser apenas let imported = require("file.json"). (2) JSON.parse deve ser assíncrono, porque usei esse código para carregar um arquivo JSON de 70 MB na memória como um objeto. Leva milissegundos dessa maneira, mas se eu usá- require()lo, ele chugs .
Kyle Baker
8
Para as pessoas que encontrarem essa resposta a partir de 2019, o Node.js. possui suporte nativo ao json para muitas e muitas versões require. Basta usar let data = require('./yourjsonfile.json')e pronto (com a nota de livro que, se o desempenho de require estiver afetando seu código, você terá problemas muito além de "querer carregar um arquivo .json")
Mike 'Pomax' Kamermans
392

A maneira mais fácil que encontrei para fazer isso é usar requiree o caminho para o seu arquivo JSON.

Por exemplo, suponha que você tenha o seguinte arquivo JSON.

test.json

{
  "firstName": "Joe",
  "lastName": "Smith"
}

Em seguida, você pode carregá-lo facilmente no aplicativo node.js. usando require

var config = require('./test.json');
console.log(config.firstName + ' ' + config.lastName);
Travis Tidwell
fonte
35
Apenas para que as pessoas saibam, e se bem me lembro, requireno nó é executado de forma síncrona. Mergulhe nas profundezas aqui
prasanthv 5/11
@Ram Funciona para mim pode ser a sua localização test.jsonseria diferente do exemplo dele. Estou usandonode 5.0
guleria
18
Outra questão / benefício com tal método é o fato de que os dados necessários é armazenado em cache, a menos que você excluir especificamente a instância em cache
magicode118
13
"require" deve ser usado para carregar módulos ou arquivo de configuração que você está usando durante toda a vida útil do seu aplicativo. não parece correto usar isso para carregar arquivos.
Yaki Klein
2
Eu diria que isso é potencialmente uma ameaça à segurança. Se o arquivo json que você está carregando contiver código JS, requireele executaria esse código? Nesse caso, você realmente precisa controlar de onde vêm os arquivos json ou um invasor pode executar códigos maliciosos em sua máquina.
sokkyoku
57

Assíncrono está lá por uma razão! Joga pedra em @mihai

Caso contrário, aqui está o código que ele usou com a versão assíncrona:

// Declare variables
var fs = require('fs'),
    obj

// Read the file and send to the callback
fs.readFile('path/to/file', handleFile)

// Write the callback function
function handleFile(err, data) {
    if (err) throw err
    obj = JSON.parse(data)
    // You can now play with your datas
}
Florian Margaine
fonte
9
concordou :), adicionado assíncrono também
mihai 04/04
1
Ótimo :-) Porém, eu não gosto de retornos de chamada em linha, isso pode levar a pesadelos de retorno de chamada que prefiro evitar.
Florian Margaine 04/04
9
Está lá por uma razão .. a menos que você queira de forma síncrona.
Matt Stephens
40

Pelo menos no Node v8.9.1, você pode simplesmente fazer

var json_data = require('/path/to/local/file.json');

e acesse todos os elementos do objeto JSON.

Alex Eftimiades
fonte
5
Essa abordagem carrega o arquivo apenas uma vez. Se você alterar os dados file.jsonapós a nova solicitação (sem reiniciar o programa) serão do primeiro carregamento. Eu não tenho fonte para fazer isso, mas eu tinha isso em aplicativo que estou construindo
Lukas Ignatavičius
Sua resposta é lamentavelmente incompleta. O que isso leva a você é um objeto, e nem se importa em implementar tostring ().
9788 David A. Gray
3
@ DavidA.Gray A questão quer poder acessar os objetos como objetos, não como seqüências de caracteres. Além da questão singleton, Lukas mencionou que esta resposta está correta.
Mikemaccana 30/01/19
2
O uso de require também executará código arbitrário no arquivo. Este método é inseguro e eu recomendaria contra.
spoulson
16

No Nó 8, você pode usar o built-in util.promisify()para ler assincronamente um arquivo como este

const {promisify} = require('util')
const fs = require('fs')
const readFileAsync = promisify(fs.readFile)

readFileAsync(`${__dirname}/my.json`, {encoding: 'utf8'})
  .then(contents => {
    const obj = JSON.parse(contents)
    console.log(obj)
  })
  .catch(error => {
    throw error
  })
JP
fonte
3
.readFilejá é assíncrono, se você está procurando a versão de sincronização, o nome é .readFileSync.
Aternus
Se você deseja usar promessas, também existe no fs/promisesnó 10. Nota: a API é experimental: nodejs.org/api/fs.html#fs_fs_promises_api
aboutaaron
@Aternus .readFileé assíncrono , mas não async. Ou seja, a função não é definida com asyncpalavras-chave, nem voltar a Promise, então você não pode fazerawait fs.readFile('whatever.json');
Kip
@ Kip, que tal um CodeSandBox?
Aternus
7

usando node-fs-extra (espera assíncrona)

const readJsonFile = async () => {
  try {
    const myJsonObject = await fs.readJson('./my_json_file.json');
    console.log(myJsonObject);
  } catch (err) {
    console.error(err)
  }
}

readJsonFile() // prints your json object
ifelse.codes
fonte
6

Usar o pacote fs-extra é bastante simples:

Sincronizar:

const fs = require('fs-extra')

const packageObj = fs.readJsonSync('./package.json')
console.log(packageObj.version) 

Assíncrono:

const fs = require('fs-extra')

const packageObj = await fs.readJson('./package.json')
console.log(packageObj.version) 
Arturo Menchaca
fonte
3
function parseIt(){
    return new Promise(function(res){
        try{
            var fs = require('fs');
            const dirPath = 'K:\\merge-xml-junit\\xml-results\\master.json';
            fs.readFile(dirPath,'utf8',function(err,data){
                if(err) throw err;
                res(data);
        })}
        catch(err){
            res(err);
        }
    });
}

async function test(){
    jsonData = await parseIt();
    var parsedJSON = JSON.parse(jsonData);
    var testSuite = parsedJSON['testsuites']['testsuite'];
    console.log(testSuite);
}

test();
Satyabrata Saha
fonte
0

Tantas respostas, e ninguém nunca fez um benchmark para comparar sincronização versus async vs exigir. Descrevi a diferença nos casos de uso da leitura de json na memória via require, readFileSync e readFile aqui .

Jehy
fonte
-1

Se você estiver procurando uma solução completa para Asynccarregar um arquivo JSON a partir do Relative PathTratamento de Erros

  // Global variables
  // Request path module for relative path
    const path = require('path')
  // Request File System Module
   var fs = require('fs');


// GET request for the /list_user page.
router.get('/listUsers', function (req, res) {
   console.log("Got a GET request for list of users");

     // Create a relative path URL
    let reqPath = path.join(__dirname, '../mock/users.json');

    //Read JSON from relative path of this file
    fs.readFile(reqPath , 'utf8', function (err, data) {
        //Handle Error
       if(!err) {
         //Handle Success
          console.log("Success"+data);
         // Parse Data to JSON OR
          var jsonObj = JSON.parse(data)
         //Send back as Response
          res.end( data );
        }else {
           //Handle Error
           res.end("Error: "+err )
        }
   });
})

Estrutura de Diretórios:

insira a descrição da imagem aqui

Hitesh Sahu
fonte