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

IT技术 javascript json
2021-02-06 11:38:03

我有以下代码让用户下载 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 数据,而不是下载它。

我进行了一些研究,这个声称可以工作,但我看不出我的代码有什么不同。

我的代码中遗漏了什么吗?

感谢您阅读我的问题:)

6个回答

这就是我为我的应用程序解决它的方法:

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();
  }
但是当您必须下载超过 2000 个字符的大文件时,这在 IE 中不起作用。
2021-03-12 11:38:03
@YASHDAVEJSON.stringify(exportObj, null, 2)改用
2021-03-17 11:38:03
这是唯一适用于超过 =~ 2000 个字符的数据的解决方案。因为您预先设置了数据:
2021-03-21 11:38:03
有人可以指出我的规范或 MDN 页面,该页面更详细地解释了整个前置数据类型的工作原理,即。“数据:文本/json;字符集=utf-8”?我正在使用它,但感觉就像魔术一样,阅读详细信息会很棒,但我什至不知道如何谷歌搜索。
2021-04-10 11:38:03
但是,这不会无限制地工作。您只能下载大约 1MB 的数据。例如,var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');在 Chrome 61 中给出“下载失败 - 网络错误”
2021-04-10 11:38:03

找到了答案。

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,他是上述代码的作者 **

您需要在 url 前添加 data: ,否则用户可能会在许多浏览器中达到 2000 个字符的限制。
2021-03-16 11:38:03
嘿,我知道这是一个旧答案,但是,知道此解决方案不适用于 IE(所有这些)IE 不熟悉下载属性参考 -链接
2021-03-29 11:38:03
@Cybear 你能向我解释一下第三行吗?
2021-04-11 11:38:03

您可以尝试使用:

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

如果你想漂亮地打印 JSON,根据这个答案,你可以使用:

JSON.stringify(data,undefined,2)
“根本不需要处理任何 HTML 元素”......并阅读 filesaver.js 的源代码......它确实如此,哈哈
2021-03-17 11:38:03
是的。我的意思是说,不需要直接处理 HTML 元素。
2021-03-17 11:38:03
FileSaver.js 对于进行简单的文件下载来说非常繁重。在下面检查我的答案;CTRL+F 并搜索“ES6+”。
2021-03-22 11:38:03
saveAs() 来自 FileSaver.js - github.com/eligrey/FileSaver.js
2021-04-06 11:38:03
这是最好的答案,因为它没有 1MB 的大小限制并且使用库而不是自定义黑客
2021-04-08 11:38:03

这将是一个纯 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

感谢您的回复,即使我问这个问题已经过去了 2 年!相比 jQuery 语法,我更喜欢纯 JS。
2021-04-02 11:38:03
您需要在 url 前添加 data: ,否则用户可能会在许多浏览器中达到 2000 个字符的限制。
2021-04-05 11:38:03
我怎样才能让这个下载在页面加载时开始。每当用户浏览页面 url 时,他都会提示下载
2021-04-06 11:38:03
今天在 Edge 中的测试:无法下载 data.json。
2021-04-08 11:38:03

以下对我有用:

/* 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");
虽然这是一个很好的答案,但它initMouseEvent()是一个已弃用的Web 标准,不应再使用。相反,使用new MouseEvent()接口。不过,这只是一个小的重构。
2021-03-13 11:38:03
@morkro 是正确的;我在下面发布了一个答案,该答案通过initMouseEvent删除来构建和改进@maia 的答案(并且代码通常已清理)
2021-04-04 11:38:03