Descargue el objeto JSON como un archivo desde el navegador


144

Tengo el siguiente código para permitir a los usuarios descargar cadenas de datos en el archivo csv.

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

Funciona bien que si el cliente ejecuta el código, genera una página en blanco y comienza a descargar los datos en un archivo csv.

Así que intenté hacer esto con un objeto JSON como

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

Pero solo veo una página con los datos JSON mostrados, no la descargo.

Investigué un poco y este dice que funciona, pero no veo ninguna diferencia en mi código.

¿Me falta algo en mi código?

Gracias por leer mi pregunta:)

Respuestas:


257

Así es como lo resolví para mi aplicación:

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

JS (JS puro, no jQuery aquí):

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

En este caso, storageObjes el objeto js que desea almacenar, y "scene.json" es solo un nombre de ejemplo para el archivo resultante.

Este enfoque tiene las siguientes ventajas sobre otras propuestas:

  • No se debe hacer clic en ningún elemento HTML
  • El resultado se nombrará como lo desee
  • no se necesita jQuery

Necesitaba este comportamiento sin hacer clic explícitamente, ya que quiero activar la descarga automáticamente en algún momento desde js.

Solución JS (no se requiere HTML):

  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
Esta es la única solución que funcionará para más de = ~ 2000 caracteres de datos. Debido a que agregó datos:
— rjurney

1
¿Alguien puede señalarme una página de especificaciones o MDN que explique con más detalle cómo funciona todo este tipo de datos antepuestos? "data: text / json; charset = utf-8"? Estoy usando esto, pero parece mágico, sería genial leer los detalles, pero ni siquiera sé cómo buscarlo en Google.
— sidewinderguy

1
Sin embargo, esto no funciona en IE cuando tienes que descargar un archivo grande con más de 2000 caracteres.
— user388969

12
Sin embargo, esto no funcionará sin límites. Solo puede descargar aproximadamente 1 MB de datos. Por ejemplo, var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');muestra "Error de descarga - Error de red" en Chrome 61
— oseiskar

1
@YASHDAVE usar JSON.stringify(exportObj, null, 2)en su lugar
— TryingToImprove

40

Encontré una respuesta.

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 bien para mi.

** Todo el crédito va a @ cowboy-ben-alman, quien es el autor del código anterior **


@Cybear, ¿puedes explicarme la tercera línea?
— Rahul Khatri

Deberá anteponer los datos: a su URL, de lo contrario es probable que el usuario alcance un límite de 2000 caracteres en muchos navegadores.
— rjurney

Hola, sé que es una respuesta anterior, pero sé que esta solución no funciona en IE (todos ellos) IE no está familiarizado con la referencia de atributo de descarga - enlace
— Ayalon Grinfeld

25

Esta sería una versión pura de JS (adaptada de 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
¡Gracias por la respuesta incluso después de que hayan pasado 2 años desde que hice esta pregunta! Prefiero JS puro sobre la sintaxis jQuery.
— Eugene Yu

Deberá anteponer los datos: a su URL, de lo contrario es probable que el usuario alcance un límite de 2000 caracteres en muchos navegadores.
— rjurney 01 de

¿Cómo puedo hacer que esta descarga comience en la carga de la página? siempre que un usuario explora la página URL que recibe pronta para descargar
— user388969

1
La prueba de hoy en Edge: data.json no se pudo descargar.
— Sarah Trees el

24

Puedes intentar usar:

No es necesario tratar con ningún 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);

Si desea imprimir bastante el JSON, según esta respuesta , puede usar:

JSON.stringify(data,undefined,2)

1
saveAs () es de FileSaver.js - github.com/eligrey/FileSaver.js
— Gautham

1
"No es necesario tratar con ningún elemento HTML" ... y leer el código fuente de filesaver.js ... hace exactamente eso jajaja
— War

1
Si. Quería decir que no es necesario tratar directamente con los elementos HTML.
— Gautham

3
Esta es la mejor respuesta, ya que no tiene un límite de tamaño de 1 MB y utiliza una biblioteca en lugar de cortes personalizados
— oseiskar

votado a favor para FileSaver ref. funcionando perfectamente
— Nadie el

15

Lo siguiente funcionó para mí:

/* 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)
}

y luego llamarlo así

saveJSON(myJsonObject, "saved_data.json");

3
Si bien esta es una gran respuesta, initMouseEvent()es un estándar web obsoleto y ya no debe usarse. En su lugar, use la new MouseEvent()interfaz. Sin embargo, es solo un refactor menor.
— morkro

10

Recientemente tuve que crear un botón que descargaría un archivo json de todos los valores de una forma grande. Necesitaba esto para trabajar con IE / Edge / Chrome. Esto es lo que hice:

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

Hubo un problema con el nombre de archivo y la extensión en Edge, pero al momento de escribir esto parecía ser un error con Edge que se debe solucionar.

Espero que esto ayude a alguien


Esto funcionó en Chrome, pero no parece funcionar en Firefox ... ¡por favor ayuda! codepen.io/anon/pen/ePYPJb
— Urmil Parikh

1
Buena función, agregue document.body.appendChild(a); a.style.display = 'none';para que funcione en Firefox.
— Fabian von Ellerts

5

Solución simple y limpia para aquellos que solo se dirigen a los 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');

Gracias, solo uno que no me dio problemas de tamaño
— Roelant

4

La downloadpropiedad de los enlaces es nueva y no es compatible con Internet Explorer (consulte la tabla de compatibilidad aquí ). Para una solución de navegador cruzado a este problema, echaría un vistazo a FileSaver.js


2

Reaccionar : agrega esto donde quieras en tu método de renderizado.

• Objeto en estado :

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

• Objeto en accesorios :

<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 y style son opcionales, modifique el estilo según sus necesidades.


1

Intente configurar otro tipo MIME: exportData = 'data:application/octet-stream;charset=utf-8,';

Pero puede haber problemas con el nombre del archivo en el cuadro de diálogo Guardar.


Perdón por volver tarde. Intenté su respuesta y descarga el archivo, pero contiene datos incorrectos. :(
— Eugene Yu

1
esto funcionó para mí ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); simplemente descarga el archivo como "descargar" pero los datos que encadené y luego codifiqué con uri son como deberían ser.
— Jason Wiener

0

Si prefiere el fragmento de consola, el raser, que el nombre de archivo, puede hacer esto:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.