Scarica l'oggetto JSON come file dal browser


144

Ho il seguente codice per consentire agli utenti di scaricare stringhe di dati nel file CSV.

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

Funziona bene che se il client esegue il codice genera una pagina vuota e inizia a scaricare i dati nel file CSV.

Quindi ho provato a farlo con l'oggetto JSON come

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

Ma vedo solo una pagina con i dati JSON visualizzati su di essa, non scaricarli.

Ho passato alcune ricerche e questo afferma di funzionare ma non vedo alcuna differenza nel mio codice.

Mi sto perdendo qualcosa nel mio codice?

Grazie per aver letto la mia domanda :)

Risposte:


257

Ecco come l'ho risolto per la mia applicazione:

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

JS (JS puro, non jQuery qui):

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

In questo caso, storageObjè l'oggetto js che si desidera memorizzare e "scene.json" è solo un nome di esempio per il file risultante.

Questo approccio presenta i seguenti vantaggi rispetto ad altri proposti:

  • Non è necessario fare clic su alcun elemento HTML
  • Il risultato verrà nominato come desiderato
  • non è necessario jQuery

Avevo bisogno di questo comportamento senza fare clic esplicito poiché desidero attivare automaticamente il download a un certo punto da js.

Soluzione JS (nessun HTML richiesto):

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

3
Questa è l'unica soluzione che funzionerà per più di = ~ 2000 caratteri di dati. Perché hai anteposto i dati:
rjurney,

1
Qualcuno può indicarmi una pagina specifica o MDN che spiega in modo più dettagliato come funziona tutto questo tipo di dati anteposto. "Dati: text / json; charset = utf-8"? Sto usando questo, ma sembra magico, sarebbe bello leggere i dettagli ma non so nemmeno come cercarlo su Google.
sidewinderguy,

1
Questo non funziona in IE anche se devi scaricare un file di grandi dimensioni con più di 2000 caratteri.
user388969,

12
Questo non funzionerà senza limiti, però. Puoi scaricare solo circa 1 MB di dati. Ad esempio, var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');fornisce "download non riuscito - errore di rete" in Chrome 61
oseiskar

1
@YASHDAVE usa JSON.stringify(exportObj, null, 2)invece
TryingToImprove

40

Ho trovato una risposta

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

sembra funzionare bene per me.

** Tutto il merito va a @ cowboy-ben-alman, che è l'autore del codice sopra **


@Cybear puoi spiegarmi la terza riga?
Rahul Khatri,

Dovrai anteporre i dati: al tuo URL, altrimenti è probabile che l'utente raggiunga un limite di 2000 caratteri in molti browser.
rjurney,

Ehi, so che è una vecchia risposta ma, so che questa soluzione non funziona su IE (tutti) IE non ha familiarità con il riferimento all'attributo del download - link
Ayalon Grinfeld

25

Questa sarebbe una versione JS pura (adattata da quella da 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


3
Grazie per la risposta anche dopo 2 anni da quando ho posto questa domanda! Preferisco JS puro rispetto alla sintassi jQuery.
Eugene Yu,

Dovrai anteporre i dati: al tuo URL, altrimenti è probabile che l'utente raggiunga un limite di 2000 caratteri in molti browser.
rjurney,

come posso far iniziare questo download al caricamento della pagina. ogni volta che un utente sfoglia l'URL della pagina, viene richiesto di scaricarlo
user388969,

1
Test di oggi su Edge: non è stato possibile scaricare data.json.
Sarah Trees,

24

Puoi provare a usare:

  • il costruttore BLOB dell'API JavaScript nativo e
  • il metodo FileSaver.js saveAs()

Non c'è bisogno di affrontare alcun 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',
    name: fileName
});

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

Se desideri stampare piuttosto JSON, per questa risposta , puoi utilizzare:

JSON.stringify(data,undefined,2)

1
saveAs () proviene da FileSaver.js - github.com/eligrey/FileSaver.js
Gautham,

1
"Non c'è bisogno di occuparsi di alcun elemento HTML" ... e leggere il codice sorgente di filesaver.js ... fa esattamente questo lol
War

1
Si. Volevo dire, non c'è bisogno di trattare direttamente con gli elementi HTML.
Gautham,

3
Questa è la risposta migliore poiché non ha un limite di dimensioni di 1 MB e utilizza una libreria invece di hack personalizzati
oseiskar

votato a favore di FileSaver ref. funziona perfettamente.
No

15

Per me ha funzionato:

/* 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 poi chiamarlo così

saveJSON(myJsonObject, "saved_data.json");

3
Sebbene questa sia un'ottima risposta, initMouseEvent()è uno standard Web deprecato e non dovrebbe più essere utilizzato. Invece, usa l' new MouseEvent()interfaccia. È solo un piccolo fattore di riflessione.
morkro,

10

Di recente ho dovuto creare un pulsante per scaricare un file json di tutti i valori di un formato grande. Ne avevo bisogno per funzionare con IE / Edge / Chrome. Questo è quello che ho fatto:

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

Si è verificato un problema con il nome file e l'estensione in Edge ma al momento della stesura questo sembrava essere un bug con Edge che doveva essere risolto.

Spero che questo aiuti qualcuno


Funzionava su Chrome, ma non sembra funzionare su Firefox ... per favore aiutatemi! codepen.io/anon/pen/ePYPJb
Urmil Parikh,

1
Bella funzione, aggiungi document.body.appendChild(a); a.style.display = 'none';per farlo funzionare in Firefox.
Fabian von Ellerts,

5

Soluzione semplice e pulita per chi si rivolge solo ai browser moderni:

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

Grazie, solo uno che non mi ha dato problemi di dimensioni
Roelant,

4

La downloadproprietà dei collegamenti è nuova e non è supportata in Internet Explorer (vedere la tabella di compatibilità qui ). Per una soluzione cross-browser a questo problema darei un'occhiata a FileSaver.js


2

Reagire : aggiungi questo dove vuoi nel tuo metodo di rendering.

• Oggetto in stato :

<a
  className="pull-right btn btn-primary"
  style={{ margin: 10 }}
  href={`data:text/json;charset=utf-8,${encodeURIComponent(
  JSON.stringify(this.state.objectToDownload)
  )}`}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

• Oggetto negli oggetti di scena :

<a
  className="pull-right btn btn-primary"
  style={{ margin: 10 }}
  href={`data:text/json;charset=utf-8,${encodeURIComponent(
  JSON.stringify(this.props.objectToDownload)
  )}`}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

className e style sono opzionali, modifica lo stile in base alle tue esigenze.


1

Prova a impostare un altro tipo MIME: exportData = 'data:application/octet-stream;charset=utf-8,';

Ma ci possono essere problemi con il nome del file nella finestra di dialogo di salvataggio.


Scusa se torno da te tardi. Ho provato la tua risposta e scarica il file ma contiene dati errati .. :(
Eugene Yu

1
questo ha funzionato per me ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); scarica semplicemente il file come "download" ma i dati che ho stretto e poi codificato con l'uri è come dovrebbero essere.
Jason Wiener,

0

Se preferisci lo snippet della console, raser, rispetto al nome del file, puoi farlo:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.