Pesquisa de site

javascript - Baixar objeto JSON como um arquivo do navegador


Eu tenho o seguinte código para permitir que os usuários baixem strings de dados em arquivo csv.

exportData = 'data:text/csv;charset=utf-8,';
exportData += 'some csv strings';
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

Funciona perfeitamente que, se o cliente executar o código, ele gera uma página em branco e começa a baixar os dados em um arquivo csv.

Então eu tentei fazer isso com um objeto JSON assim

exportData = 'data:text/json;charset=utf-8,';
exportData += escape(JSON.stringify(jsonObject));
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

Mas eu vejo apenas uma página com os dados JSON exibidos nela, não baixando-os.

Eu fiz algumas pesquisas e esta diz funcionar, mas eu não vejo nenhuma diferença no meu código.

Estou errando algo no meu código?

Obrigado por ler minha pergunta:)

Resposta #1

É assim que eu resolvi isso para a minha aplicação:

HTML: <a id="downloadAnchorElem" style="display:none"></a>

JS (JS puro, não jQuery aqui):

var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(storageObj));
var dlAnchorElem = document.getElementById('downloadAnchorElem');
dlAnchorElem.setAttribute("href",     dataStr     );
dlAnchorElem.setAttribute("download", "scene.json");
dlAnchorElem.click();

Neste caso, storageObj é o objeto js que você quer armazenar, e "scene.json" é apenas um nome de exemplo para o arquivo resultante.

Esta abordagem possui as seguintes vantagens em relação a outras propostas:

  • Nenhum elemento HTML precisa ser clicado
  • O resultado será nomeado como você quiser
  • não é necessário jQuery

Eu precisava desse comportamento sem cliques explícitos, pois quero disparar o download automaticamente em algum momento a partir do JS.

Solução em JS (html não necessário):

  function downloadObjectAsJson(exportObj, exportName){
    var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
    var downloadAnchorNode = document.createElement('a');
    downloadAnchorNode.setAttribute("href",     dataStr);
    downloadAnchorNode.setAttribute("download", exportName + ".json");
    document.body.appendChild(downloadAnchorNode); // required for firefox
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
  }

Editar: Se você quiser formatar o JSON com alguns espaços em branco para melhor legibilidade, você pode usar os parâmetros adicionais da função stringify para isso:

  JSON.stringify(exportObj, null, 2)

Veja JSON.stringify no MDN, obrigado TryingToImprove pela dica!

Resposta #2

Você poderia tentar usar:

  • o construtor Blob da API nativa do JavaScript e
  • o método saveAs() do FileSaver.js

Não há necessidade de lidar com nenhum elemento HTML.

var data = {
    key: 'value'
};
var fileName = 'myData.json';

// Create a blob of the data
var fileToSave = new Blob([JSON.stringify(data)], {
    type: 'application/json'
});

// Save the file
saveAs(fileToSave, fileName);

Se você quisesse formatar o JSON de forma legível, conforme esta resposta, você poderia usar:

JSON.stringify(data,undefined,2)

Resposta #3

Encontrei uma resposta.

var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));

$('<a href="data:' + data + '" download="data.json">download JSON</a>').appendTo('#container');

parece funcionar bem para mim.

** Todo o crédito vai para @cowboy-ben-alman, que é o autor do código acima **

Resposta #4

Versão ES6+ para 2021; sem limite de 1MB também:

Isto é adaptado da versão de @maia, atualizada para Javascript moderno com o initMouseEvent obsoleto substituído por new MouseEvent() e o código geralmente melhorado:

const saveTemplateAsFile = (filename, dataObjToWrite) => {
    const blob = new Blob([JSON.stringify(dataObjToWrite)], { type: "text/json" });
    const link = document.createElement("a");

    link.download = filename;
    link.href = window.URL.createObjectURL(blob);
    link.dataset.downloadurl = ["text/json", link.download, link.href].join(":");

    const evt = new MouseEvent("click", {
        view: window,
        bubbles: true,
        cancelable: true,
    });

    link.dispatchEvent(evt);
    link.remove()
};

Se você quiser passar um objeto:

saveTemplateAsFile("filename.json", myDataObj);

Resposta #5

Solução simples e limpa para aqueles que apenas miram navegadores modernos:

function downloadTextFile(text, name) {
  const a = document.createElement('a');
  const type = name.split(".").pop();
  a.href = URL.createObjectURL( new Blob([text], { type:`text/${type === "txt" ? "plain" : type}` }) );
  a.download = name;
  a.click();
}

downloadTextFile(JSON.stringify(myObj), 'myObj.json');

Resposta #6

Esta seria uma versão pura em JS (adaptada do cowboy):

var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));

var a = document.createElement('a');
a.href = 'data:' + data;
a.download = 'data.json';
a.innerHTML = 'download JSON';

var container = document.getElementById('container');
container.appendChild(a);

http://jsfiddle.net/sz76c083/1

Resposta #7

O seguinte funcionou para mim:

/* function to save JSON to file from browser
* adapted from http://bgrins.github.io/devtools-snippets/#console-save
* @param {Object} data -- json object to save
* @param {String} file -- file name to save to 
*/
function saveJSON(data, filename){

    if(!data) {
        console.error('No data')
        return;
    }

    if(!filename) filename = 'console.json'

    if(typeof data === "object"){
        data = JSON.stringify(data, undefined, 4)
    }

    var blob = new Blob([data], {type: 'text/json'}),
        e    = document.createEvent('MouseEvents'),
        a    = document.createElement('a')

    a.download = filename
    a.href = window.URL.createObjectURL(blob)
    a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
    e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
    a.dispatchEvent(e)
}

e então chamá-lo assim

saveJSON(myJsonObject, "saved_data.json");

Resposta #8

Recentemente, eu tive que criar um botão que baixasse um arquivo json com todos os valores de um formulário grande. Eu precisava que isso funcionasse no IE/Edge/Chrome. Isto é o que eu fiz:

function download(text, name, type)
    {
        var file = new Blob([text], {type: type});
        var isIE = /*@cc_on!@*/false || !!document.documentMode;
        if (isIE)
        {
            window.navigator.msSaveOrOpenBlob(file, name);
        }
        else
        {
            var a = document.createElement('a');
            a.href = URL.createObjectURL(file);
            a.download = name;
            a.click();
        }
     }

download(jsonData, 'Form_Data_.json','application/json');

Havia um problema com o nome do arquivo e a extensão no Edge, mas no momento em que isto foi escrito parecia ser um bug do Edge que está prestes a ser corrigido.

Espero que isso ajude alguém

Artigos relacionados