从浏览器下载JSON对象作为文件


144

我有以下代码,可让用户下载csv文件中的数据字符串。

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

如果客户端运行代码,它将生成空白页并开始下载csv文件中的数据,效果很好。

所以我试图用JSON对象来做到这一点

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

但是我只看到一个页面,上面显示了JSON数据,没有下载它。

我进行了一些研究,并且研究声称可以工作,但是我的代码没有任何区别。

我在代码中缺少什么吗?

感谢您阅读我的问题:)

Answers:


257

这是我为应用程序解决的方式:

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

JS(纯JS,此处不是jQuery):

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

在这种情况下,storageObj您要存储的是js对象,而“ scene.json”只是结果文件的示例名称。

与其他提议的方法相比,此方法具有以下优点:

  • 无需单击HTML元素
  • 结果将根据您的需要命名
  • 不需要jQuery

我需要这种行为而无需显式单击,因为我想在某个时候从js自动触发下载。

JS解决方案(无需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
这是唯一适用于=〜2000个字符的数据的解决方案。因为您添加了数据,所以:
rjurney

1
有人可以将我指向规范或MDN页面,该页面更详细地解释了整个前置数据类型的工作原理。“ data:text / json; charset = utf-8”?我正在使用它,但是感觉像魔术一样,阅读详细信息会很棒,但是我什至不知道如何用谷歌搜索它。
sidewinderguy

1
但是,当您必须下载超过2000个字符的大文件时,这在IE中不起作用。
user388969

12
但是,这将无止境。您只能下载大约1MB的数据。例如,var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');在Chrome 61中显示“下载失败-网络错误”
oseiskar '17

1
使用@YASHDAVE JSON.stringify(exportObj, null, 2)代替
TryingToImprove

40

找到了答案。

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

似乎对我来说很好。

**所有功劳归于@ cowboy-ben-alman,他是上述代码的作者**


@Cybear您能向我解释第三行吗?
拉胡尔·哈特里

您可能希望在数据之前添加数据:,否则用户可能会在许多浏览器中达到2000个字符的限制。
rjurney

嘿,我知道这是一个旧答案,但是,知道此解决方案不适用于IE(所有人)IE不熟悉下载属性参考- 链接
Ayalon Grinfeld

25

这将是纯JS版本(改编自牛仔):

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
自从我问了这个问题已经2年了,也感谢您的答复!我更喜欢纯JS而不是jQuery语法。
尤金·于

您可能希望在数据之前添加数据:,否则用户可能会在许多浏览器中达到2000个字符的限制。
rjurney

我如何才能使此下载从页面加载开始。每当用户浏览页面URL时,他都会得到下载提示
user388969 '17

1
Edge中的今天测试:无法下载data.json。
莎拉·树

24

您可以尝试使用:

根本不需要处理任何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);

如果您想漂亮地打印JSON,请按照以下答案使用:

JSON.stringify(data,undefined,2)

1
saveAs()来自FileSaver.js-github.com/eligrey/FileSaver.js
Gautham

1
“根本不需要处理任何HTML元素”……并阅读filesaver.js的源代码……它确实做到了大声笑
War

1
是的 我的意思是说,无需直接处理HTML元素。
Gautham'9

3
这是最好的答案,因为它没有1MB的大小限制,而是使用库而不是自定义的hack
oseiskar

为FileSaver参考投票。工作完美。

15

以下为我工作:

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

然后这样称呼它

saveJSON(myJsonObject, "saved_data.json");

3
尽管这是一个很好的答案,但initMouseEvent()它是已弃用的 Web标准,因此不再应使用。而是使用new MouseEvent()界面。不过,这只是一个较小的重构。
莫尔克罗(Morkro)'17年

10

我最近不得不创建一个按钮,该按钮将下载所有具有大格式值的json文件。我需要它与IE / Edge / Chrome一起使用。这是我所做的:

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

Edge中的文件名和扩展名存在一个问题,但是在撰写本文时,这似乎是Edge的一个错误,应予以修复。

希望这可以帮助某人


这适用于Chrome,但似乎不适用于Firefox ...请帮助!codepen.io/anon/pen/ePYPJb
Urmil Parikh

1
不错的功能,添加document.body.appendChild(a); a.style.display = 'none';使其可以在Firefox中使用。
Fabian von Ellerts,

5

针对仅针对现代浏览器的用户的简单,干净的解决方案:

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

谢谢,只有一个没有给我尺寸问题的
东西-Roelant

4

download链接的属性是新属性,Internet Explorer不支持链接的属性(请参阅此处的兼容性表)。对于这个问题的跨浏览器解决方案,我来看看FileSaver.js


2

React:在渲染方法中添加所需的位置。

状态中的对象:

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

道具中的物体:

<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和style是可选的,请根据需要修改样式。


1

尝试设置另一个MIME类型: exportData = 'data:application/octet-stream;charset=utf-8,';

但是保存对话框中的文件名可能存在问题。


对不起,您迟到了。我尝试了您的答案,它确实下载了文件,但其中包含错误的数据。.::
Eugene Yu

1
这对我有用... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); 它只是将文件下载为“下载”,但是我将数据进行了字符串化,然后进行了uri编码,这是应该的。
杰森·维纳

0

如果您更喜欢控制台代码片段,而不是文件名,则可以执行以下操作:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.